From 2d4d51fff7624b0b3b274445230299ed6264c11f Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Thu, 16 Jul 2026 12:34:27 -0700 Subject: [PATCH 01/11] Vendor OpenAPI spec and add generation pipeline Adds the Omni OpenAPI 3.1 spec (from the omni repo, also served at /openapi.json), a preprocessing script that collapses zod-to-openapi allOf-description wrappers and stubs recursive layout/vis schemas, an openapi-python-client config, and scripts/generate.sh to regenerate the package. Co-Authored-By: Claude Fable 5 --- MANIFEST.in | 2 - generator/config.yaml | 3 + requirements.txt | 7 - scripts/generate.sh | 41 + scripts/preprocess_spec.py | 93 + setup.py | 25 - spec/openapi.json | 50713 ++++++++++++++++++++++++++++++++++ spec/openapi.processed.json | 25769 +++++++++++++++++ 8 files changed, 76619 insertions(+), 34 deletions(-) delete mode 100644 MANIFEST.in create mode 100644 generator/config.yaml delete mode 100644 requirements.txt create mode 100755 scripts/generate.sh create mode 100644 scripts/preprocess_spec.py delete mode 100644 setup.py create mode 100644 spec/openapi.json create mode 100644 spec/openapi.processed.json diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 04f196a..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,2 +0,0 @@ -include README.md -include LICENSE diff --git a/generator/config.yaml b/generator/config.yaml new file mode 100644 index 0000000..c4ebde6 --- /dev/null +++ b/generator/config.yaml @@ -0,0 +1,3 @@ +literal_enums: true +project_name_override: omni-python-sdk +package_name_override: omni_python_sdk diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 2a7e1d8..0000000 --- a/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -requests -pyarrow -ndjson -pandas -matplotlib -statsmodels -load-dotenv \ No newline at end of file diff --git a/scripts/generate.sh b/scripts/generate.sh new file mode 100755 index 0000000..c3aa0a9 --- /dev/null +++ b/scripts/generate.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Regenerate the omni_python_sdk package from the OpenAPI spec. +# +# Usage: +# scripts/generate.sh # regenerate from the checked-in spec/openapi.json +# scripts/generate.sh --source # sync spec from a local omni repo checkout first +# scripts/generate.sh --url # sync spec from a live instance (fetches /openapi.json) +# +# Requires: openapi-python-client (pip install openapi-python-client), rsync. +# Hand-written files (omni_python_sdk/helpers.py) are preserved. + +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +SPEC="$REPO_ROOT/spec/openapi.json" +PROCESSED="$REPO_ROOT/spec/openapi.processed.json" +CONFIG="$REPO_ROOT/generator/config.yaml" +PKG="$REPO_ROOT/omni_python_sdk" + +if [[ "${1:-}" == "--source" ]]; then + cp "$2" "$SPEC" + echo "synced spec from $2" +elif [[ "${1:-}" == "--url" ]]; then + curl -fsSL "${2%/}/openapi.json" -o "$SPEC" + echo "synced spec from ${2%/}/openapi.json" +fi + +python "$REPO_ROOT/scripts/preprocess_spec.py" "$SPEC" "$PROCESSED" + +TMPDIR_GEN="$(mktemp -d)" +trap 'rm -rf "$TMPDIR_GEN"' EXIT + +openapi-python-client generate \ + --path "$PROCESSED" \ + --config "$CONFIG" \ + --output-path "$TMPDIR_GEN/out" \ + --overwrite + +rsync -a --delete --exclude helpers.py "$TMPDIR_GEN/out/omni_python_sdk/" "$PKG/" + +echo "regenerated $PKG" diff --git a/scripts/preprocess_spec.py b/scripts/preprocess_spec.py new file mode 100644 index 0000000..2c1ef97 --- /dev/null +++ b/scripts/preprocess_spec.py @@ -0,0 +1,93 @@ +"""Preprocess the raw Omni OpenAPI spec for openapi-python-client. + +The spec is generated by zod-to-openapi, which emits two constructs the +generator can't handle: + +1. `allOf: [, {description: ...}]` wrappers produced by zod's + `.describe()` — collapsed to the inner schema. +2. A handful of deeply recursive document-layout / visualization schemas — + stubbed out as free-form objects so the rest of the client still generates + with full endpoint coverage. Callers pass/receive plain dicts for these. + +Usage: python scripts/preprocess_spec.py spec/openapi.json spec/openapi.processed.json +""" + +import json +import sys + +OBJ = {"type": "object", "additionalProperties": True} +ARR = {"type": "array", "items": {"type": "object", "additionalProperties": True}} + +# Schemas replaced with free-form stubs (recursive or too dynamic to model). +STUBS = { + "JsonValue": OBJ, + "GridContainer": OBJ, + "StackContainer": OBJ, + "PageContainer": OBJ, + "ReferenceContainer": OBJ, + "Containers": ARR, + "ControlReadExternal": OBJ, + "ControlsReadExternal": OBJ, + "ControlPatchExternal": OBJ, + "ControlsPatchExternal": OBJ, + "QueryPresentationReadExternal": OBJ, + "QueryPresentationsReadExternal": OBJ, + "QueryPresentationPatchExternal": OBJ, + "QueryPresentationsPatchExternal": OBJ, + "ApiVisConfig": OBJ, + "AiSemanticQuery": OBJ, +} + +ANNOTATION_KEYS = {"description", "example", "examples", "default", "deprecated", "title"} + + +def is_annotation_only(node): + return isinstance(node, dict) and set(node.keys()) <= ANNOTATION_KEYS + + +def collapse_allof(node): + """zod .describe() pattern: allOf: [X, {description}] -> X.""" + if isinstance(node, dict) and isinstance(node.get("allOf"), list): + real = [m for m in node["allOf"] if not is_annotation_only(m)] + if len(real) == 1: + rest = {k: v for k, v in node.items() if k != "allOf"} + new = dict(real[0]) + if "$ref" in new: + # Siblings alongside $ref are ignored inconsistently by tools; + # keep the bare reference. + new = {"$ref": new["$ref"]} + else: + for k, v in rest.items(): + new.setdefault(k, v) + node.clear() + node.update(new) + + +def walk(node, fn): + if isinstance(node, dict): + fn(node) + for v in node.values(): + walk(v, fn) + elif isinstance(node, list): + for v in node: + walk(v, fn) + + +def main(src, dst): + with open(src) as f: + spec = json.load(f) + schemas = spec["components"]["schemas"] + for name, stub in STUBS.items(): + if name in schemas: + desc = schemas[name].get("description", "") + new = dict(stub) + new["description"] = (desc + " (Not statically modeled; use plain dicts.)").strip() + schemas[name] = new + walk(spec, collapse_allof) + with open(dst, "w") as f: + json.dump(spec, f, indent=2) + print(f"wrote {dst}") + + +if __name__ == "__main__": + main(sys.argv[1], sys.argv[2]) diff --git a/setup.py b/setup.py deleted file mode 100644 index 55bbfa5..0000000 --- a/setup.py +++ /dev/null @@ -1,25 +0,0 @@ -from setuptools import setup, find_packages - -setup( - name='omni_python_sdk', - version='0.1.11', - description='A Python SDK for Omni API', - long_description=open('README.md').read(), - long_description_content_type='text/markdown', - author='Jamie Davidson', - author_email='jamie@omni.co', - url='https://github.com/exploreomni/omni-python-sdk', - packages=find_packages(), - install_requires=[ - 'requests', - 'pyarrow', - 'ndjson', - 'dotenv' - ], - classifiers=[ - 'Programming Language :: Python :: 3', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - ], - python_requires='>=3.9', -) diff --git a/spec/openapi.json b/spec/openapi.json new file mode 100644 index 0000000..966e3f2 --- /dev/null +++ b/spec/openapi.json @@ -0,0 +1,50713 @@ +{ + "info": { + "description": "The Omni API enables programmatic access to dashboards, documents, models, and other resources.", + "title": "Omni API", + "version": "1.0.0" + }, + "openapi": "3.1.0", + "security": [ + { + "bearerAuth": [] + } + ], + "tags": [ + { + "description": "AI-powered data analysis. Submit natural language questions as synchronous queries or asynchronous jobs, and retrieve results including generated queries, data, and summarized answers.", + "name": "AI" + }, + { + "description": "Saved AI prompts that fire on a schedule and deliver the response to email recipients.", + "name": "AI Routines" + }, + { + "description": "AI evaluation: manage prompt sets and runs used to score AI quality against curated prompt suites.", + "name": "AI Eval" + }, + { + "description": "AI-generated model suggestions: list, generate, schedule, and manage suggested improvements to a shared model.", + "name": "AI Model Suggestions" + }, + { + "description": "API token management", + "name": "API Tokens" + }, + { + "description": "Database connections and environments", + "name": "Connections" + }, + { + "description": "Content retrieval", + "name": "Content" + }, + { + "description": "Dashboard downloads and filters", + "name": "Dashboards" + }, + { + "description": "Document and workbook management", + "name": "Documents" + }, + { + "description": "Embedded SSO session management", + "name": "Embed" + }, + { + "description": "Folder organization and permissions", + "name": "Folders" + }, + { + "description": "Label management", + "name": "Labels" + }, + { + "description": "Semantic model management", + "name": "Models" + }, + { + "description": "Query execution", + "name": "Query" + }, + { + "description": "Schedule management and delivery", + "name": "Schedules" + }, + { + "description": "SCIM provisioning", + "name": "SCIM" + }, + { + "description": "Unstable API routes - subject to change", + "name": "Unstable" + }, + { + "description": "File upload management", + "name": "Uploads" + }, + { + "description": "User attribute definitions management", + "name": "User Attributes" + }, + { + "description": "User and group management", + "name": "Users" + }, + { + "description": "Self-introspection: the authenticated caller can discover their own identity, key scope, org role, and resolved per-model permissions.", + "name": "Whoami" + } + ], + "components": { + "securitySchemes": { + "bearerAuth": { + "bearerFormat": "API Token", + "description": "Include in the Authorization header as: Authorization: Bearer ", + "scheme": "bearer", + "type": "http" + } + }, + "schemas": { + "DbtEnvironmentVariableUpdate": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Existing variable ID" + }, + "isSecret": { + "type": "boolean", + "description": "Whether the variable value is secret" + }, + "value": { + "type": [ + "string", + "null" + ], + "description": "Updated variable value. Omit or set to null to keep the existing value for secret variables." + } + }, + "required": [ + "id", + "isSecret" + ], + "additionalProperties": false, + "description": "Update an existing variable by ID. Variable names cannot be changed after creation.", + "title": "DbtEnvironmentVariableUpdate" + }, + "CompositeFilter": { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + } + }, + "required": [ + "kind", + "type", + "values" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + } + }, + "required": [ + "kind", + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + } + }, + "required": [ + "type", + "user_attribute_name" + ] + }, + { + "$ref": "#/components/schemas/CompositeFilter" + } + ] + }, + "description": "Child filters — each a simple filter or another composite filter. Recursive; see the dashboard-filters reference for the full grammar." + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + } + }, + "required": [ + "conjunction", + "filters", + "type" + ] + }, + "AiGenerateQueryResponse": { + "type": "object", + "properties": { + "baseView": { + "type": [ + "string", + "null" + ], + "description": "The base view name used for query generation when queryAllViews surfaced a non-topic view. Mutually exclusive with `topic` — exactly one is non-null when a query was generated.", + "example": null + }, + "downgradedModelTier": { + "type": "string", + "description": "Present only when the organization is over its AI downgrade threshold, signaling the query was generated on a downgraded (cheaper) model tier (e.g. 'haiku') to conserve credits. Advisory and best-effort — the call still succeeds, and clients may surface that a downgraded model was used. Absent when no downgrade applied.", + "example": "haiku" + }, + "error": { + "type": [ + "object", + "null" + ], + "properties": { + "detail": { + "type": "string", + "description": "Detailed error message explaining why query generation failed.", + "example": "The AI was unable to generate a query for this prompt. Try rephrasing your question to be more specific about the data you want to retrieve." + }, + "message": { + "type": "string", + "description": "Short error summary.", + "example": "No query generated" + } + }, + "required": [ + "detail", + "message" + ], + "description": "Error details if query generation failed. Null on success." + }, + "query": { + "$ref": "#/components/schemas/AiSemanticQuery" + }, + "result": { + "type": "object", + "additionalProperties": {}, + "description": "Query execution results as a JSON object. Only present when runQuery is true (the default) and the query executed successfully. The structure contains the query result data." + }, + "topic": { + "type": [ + "string", + "null" + ], + "description": "The topic name used for query generation. Mutually exclusive with `baseView` — exactly one is non-null when a query was generated.", + "example": "order_items" + }, + "workbookUrl": { + "type": "string", + "format": "uri", + "description": "URL to view and edit the generated query in an Omni workbook. Only present when workbookUrl was set to true in the request.", + "example": "https://myorg.omni.co/w/abc123/1" + } + }, + "required": [ + "error", + "query" + ] + }, + "AiSemanticQuery": { + "type": [ + "object", + "null" + ], + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of fully qualified field names to include in the query (e.g., \"view_name.field_name\").", + "example": [ + "products.name", + "order_items.total_revenue" + ] + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "description": "Filter conditions keyed by fully qualified field name. Filter values vary by field type." + }, + "limit": { + "type": "integer", + "description": "Maximum number of rows to return.", + "example": 500 + }, + "sorts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiQuerySort" + }, + "description": "Sort specifications applied to the query results." + }, + "table": { + "type": "string", + "description": "The base topic or view name for the query.", + "example": "order_items" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {}, + "description": "The generated semantic query definition. Null if generation failed. This query can be passed directly to the POST /api/v1/query/run endpoint." + }, + "AiQuerySort": { + "type": "object", + "properties": { + "column_name": { + "type": "string", + "description": "Fully qualified field name to sort by (e.g., \"view_name.field_name\").", + "example": "order_items.total_revenue" + }, + "sort_descending": { + "type": "boolean", + "description": "Whether to sort in descending order.", + "example": true + } + }, + "required": [ + "column_name", + "sort_descending" + ] + }, + "ApiError400": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Bad Request: prompt: Required" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 400 + } + }, + "required": [ + "detail", + "status" + ] + }, + "ApiError401": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Unauthorized: Missing or invalid API key" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 401 + } + }, + "required": [ + "detail", + "status" + ] + }, + "AiCreditShutoffError": { + "type": "object", + "properties": { + "code": { + "type": "string", + "enum": [ + "shutoff" + ], + "description": "Stable reason code identifying an AI-credit shutoff.", + "example": "shutoff" + }, + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "The AI credit limit has been reached. Contact your administrator for assistance." + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 402 + } + }, + "required": [ + "code", + "detail", + "status" + ] + }, + "ApiError403": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Forbidden: AI query generation is not enabled for this organization" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 403 + } + }, + "required": [ + "detail", + "status" + ] + }, + "ApiError404": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Model 770e8400-e29b-41d4-a716-446655440002 not found" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 404 + } + }, + "required": [ + "detail", + "status" + ] + }, + "AiGenerateQueryBody": { + "allOf": [ + { + "$ref": "#/components/schemas/AiTopicParams" + }, + { + "type": "object", + "properties": { + "prompt": { + "type": "string", + "description": "The natural language prompt describing the data you want to retrieve.", + "example": "Show me total revenue by month for the last year" + }, + "queryAllViews": { + "type": "boolean", + "description": "If true and the model has query_all_views_and_fields enabled, AI can query views not in any topic." + }, + "runQuery": { + "type": "boolean", + "description": "Whether to execute the generated query and return results. Defaults to true. Set to false to only generate the query definition without executing it.", + "example": true + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID to execute the query as. Their permissions will be applied for row-level security. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", + "example": "990e8400-e29b-41d4-a716-446655440004" + }, + "workbookUrl": { + "type": "boolean", + "description": "If true, creates a new workbook with the generated query and returns its URL. Useful for sharing results or further exploration.", + "example": false + } + }, + "required": [ + "prompt" + ] + } + ] + }, + "AiTopicParams": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "currentTopicName": { + "type": "string", + "description": "The name of the current topic to scope query generation. If not provided, AI will automatically select the best topic for your prompt.", + "example": "order_items" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The UUID of the shared model to query against. Only shared models are supported.", + "example": "770e8400-e29b-41d4-a716-446655440002" + } + }, + "required": [ + "modelId" + ] + }, + "AiPickTopicResponse": { + "type": "object", + "properties": { + "topicId": { + "type": "string", + "description": "The name of the topic that best matches the prompt. Use this as the topicName parameter when calling generate-query or submitting an AI job.", + "example": "order_items" + } + }, + "required": [ + "topicId" + ] + }, + "AiPickTopicBody": { + "allOf": [ + { + "$ref": "#/components/schemas/AiTopicParams" + }, + { + "type": "object", + "properties": { + "potentialTopicNames": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional list of topic names to limit consideration to. If not provided, all topics the user has access to in the model will be evaluated.", + "example": [ + "order_items", + "customers", + "products" + ] + }, + "prompt": { + "type": "string", + "description": "The natural language prompt to analyze. The AI will determine which topic best matches the data described in this prompt.", + "example": "How many orders were placed last month?" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID to evaluate topic access as. Their permissions will be used for permission-aware topic selection. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", + "example": "990e8400-e29b-41d4-a716-446655440004" + } + }, + "required": [ + "prompt" + ] + } + ] + }, + "AiSearchOmniDocsResponse": { + "type": "object", + "properties": { + "answer": { + "type": "string", + "description": "A synthesized answer to the question, based on the Omni documentation.", + "example": "To create a dashboard filter, navigate to your dashboard and click the \"Add Filter\" button..." + }, + "sources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "The title of the source documentation page.", + "example": "Dashboard Filters" + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL of the source documentation page.", + "example": "https://docs.omni.co/docs/dashboards/filters" + } + }, + "required": [ + "title", + "url" + ] + }, + "description": "List of documentation pages that were used to synthesize the answer." + } + }, + "required": [ + "answer", + "sources" + ] + }, + "AiSearchOmniDocsBody": { + "type": "object", + "properties": { + "question": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "description": "A natural language question about Omni features, configuration, modeling, dashboards, or other topics covered in the Omni documentation.", + "example": "How do I create a dashboard filter?" + } + }, + "required": [ + "question" + ] + }, + "AiJobSubmitResponse": { + "type": "object", + "properties": { + "conversationId": { + "type": "string", + "format": "uuid", + "description": "The conversation ID for this job. Pass this as conversationId in subsequent job submissions to continue the conversation with additional context.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "jobId": { + "type": "string", + "format": "uuid", + "description": "The unique identifier for the created job. Use this to poll status via GET /api/v1/ai/jobs/{jobId} or retrieve results via GET /api/v1/ai/jobs/{jobId}/result.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "omniChatUrl": { + "type": "string", + "format": "uri", + "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" + } + }, + "required": [ + "conversationId", + "jobId", + "omniChatUrl" + ] + }, + "ApiError409": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "An active job already exists for this conversation" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 409 + } + }, + "required": [ + "detail", + "status" + ] + }, + "AiJobSubmitBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId. Use this to query against in-progress model changes.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "conversationId": { + "type": "string", + "format": "uuid", + "description": "Conversation ID to continue an existing conversation thread. The AI will have access to the context from previous jobs in the same conversation. If omitted, a new conversation is created. Only one active job can exist per conversation.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The UUID of the model to query against. Must be a shared model, or a shared-extension model usable as a workbook base.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "progressWebhookEnabled": { + "type": "boolean", + "default": false, + "description": "When true, real-time progress events are POSTed to webhookUrl during execution (e.g., \"Searching for revenue fields\", \"Query returned 42 rows\"). Requires webhookUrl. Progress events are best-effort: single attempt, no retries, failures do not affect job execution.", + "example": true + }, + "prompt": { + "type": "string", + "minLength": 1, + "description": "The natural language prompt for the AI to process. The AI will analyze your question, generate appropriate queries, execute them, and return a summarized answer.", + "example": "What are the top 5 products by revenue this quarter?" + }, + "topicName": { + "type": "string", + "maxLength": 256, + "description": "Topic name to scope query generation. Topics define a set of related views and their join paths. If not provided, the AI will automatically select the best topic. Use the pick-topic endpoint to determine the right topic programmatically.", + "example": "order_items" + }, + "webhookMetadata": { + "type": "object", + "additionalProperties": {}, + "description": "Arbitrary metadata object that will be included unchanged in webhook payloads. Use this to correlate webhook notifications with your own system (e.g., tracking IDs, channel references).", + "example": { + "externalId": "task-123", + "slackChannel": "C0123456789" + } + }, + "webhookSigningSecret": { + "type": "string", + "description": "Secret key for HMAC-SHA256 webhook payload signing. When provided, each webhook request includes X-Omni-Signature and X-Omni-Signature-Timestamp headers for verification. Required if webhookUrl is specified." + }, + "webhookUrl": { + "type": "string", + "format": "uri", + "description": "URL to receive webhook POSTs. Always receives a terminal event (job.complete, job.failed, or job.denied) when the job finishes; a job.denied event (e.g. the organization is over its AI credit limit) additionally carries a reason field. When progressWebhookEnabled is true, also receives real-time progress events during execution.", + "example": "https://example.com/webhooks/omni" + } + }, + "required": [ + "modelId", + "prompt" + ] + }, + "AiJobStatusResponse": { + "type": "object", + "properties": { + "branchId": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Branch ID used for model context, or null if querying the main shared model." + }, + "cancelledAt": { + "type": "string", + "format": "date-time", + "description": "When the job was cancelled. Only present in CANCELLED state.", + "example": "2025-01-15T10:00:12.000Z" + }, + "cancelledBy": { + "type": "string", + "format": "uuid", + "description": "User ID of who cancelled the job. Only present in CANCELLED state.", + "example": "990e8400-e29b-41d4-a716-446655440004" + }, + "completedAt": { + "type": "string", + "format": "date-time", + "description": "When the job finished (successfully or with error). Present in COMPLETE and FAILED states.", + "example": "2025-01-15T10:01:30.000Z" + }, + "conversationId": { + "type": "string", + "format": "uuid", + "description": "The conversation this job belongs to. Use this to submit follow-up jobs in the same conversation thread.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When the job was submitted.", + "example": "2025-01-15T10:00:00.000Z" + }, + "error": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Machine-readable error code.", + "example": "QUERY_EXECUTION_ERROR" + }, + "detail": { + "type": "string", + "description": "Additional error detail or context.", + "example": "The query timed out after 300 seconds" + }, + "message": { + "type": "string", + "description": "Human-readable error message.", + "example": "Column 'revenue' not found in table 'orders'" + } + }, + "required": [ + "message" + ], + "additionalProperties": {}, + "description": "Error details explaining why the job failed. Only present in FAILED state." + }, + "executionStartedAt": { + "type": "string", + "format": "date-time", + "description": "When execution began. Present once the job transitions from QUEUED to EXECUTING. May be absent on jobs that failed or were cancelled before execution started.", + "example": "2025-01-15T10:00:05.000Z" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique identifier for this job.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "modelId": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "The shared model ID used for query generation.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "omniChatUrl": { + "type": "string", + "format": "uri", + "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" + }, + "organizationId": { + "type": "string", + "format": "uuid", + "description": "The organization that owns this job.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "progress": { + "type": [ + "object", + "null" + ], + "properties": { + "iteration": { + "type": "integer", + "description": "Current iteration number. The AI may take multiple iterations to refine queries and generate a complete answer.", + "example": 2 + }, + "message": { + "type": "string", + "description": "Human-readable status message describing what the AI is currently doing.", + "example": "Running query: Top products by revenue" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When this progress update was recorded.", + "example": "2025-01-15T10:00:08.000Z" + } + }, + "required": [ + "iteration", + "message", + "updatedAt" + ], + "description": "Real-time progress information. Only present in EXECUTING state. Null if no progress has been reported yet. Updated in real-time as the AI works through iterations." + }, + "prompt": { + "type": "string", + "description": "The natural language prompt that was submitted.", + "example": "What are the top 5 products by revenue?" + }, + "resultSummary": { + "type": "string", + "description": "Markdown-formatted summary of the job result. Only present in COMPLETE state. For the full result with query details and data, use GET /api/v1/ai/jobs/{jobId}/result.", + "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + }, + "state": { + "type": "string", + "enum": [ + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED" + ], + "description": "Current state of the job. Terminal states are COMPLETE, FAILED, and CANCELLED. Poll until the job reaches a terminal state.", + "example": "QUEUED" + }, + "topicName": { + "type": [ + "string", + "null" + ], + "description": "Topic name used to scope query generation, or null if the AI selected the topic automatically.", + "example": "order_items" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When the job record was last modified.", + "example": "2025-01-15T10:00:05.000Z" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "The user ID who created (or is associated with) this job.", + "example": "990e8400-e29b-41d4-a716-446655440004" + } + }, + "required": [ + "branchId", + "conversationId", + "createdAt", + "id", + "modelId", + "omniChatUrl", + "organizationId", + "prompt", + "state", + "topicName", + "updatedAt", + "userId" + ] + }, + "AiJobCancelResponse": { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "format": "uuid", + "description": "The job ID that was requested to cancel.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "state": { + "type": "string", + "enum": [ + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED" + ], + "description": "The job state after the cancellation attempt. CANCELLED if the cancellation was successful. If the job was already in a terminal state (COMPLETE, FAILED, CANCELLED), the current state is returned unchanged — the endpoint is idempotent.", + "example": "CANCELLED" + } + }, + "required": [ + "jobId", + "state" + ] + }, + "AiJobResultResponse": { + "type": "object", + "properties": { + "actions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiJobAction" + }, + "description": "Ordered list of actions the AI took during execution. Each action represents a step such as generating a query, executing it, or synthesizing a final answer." + }, + "message": { + "type": "string", + "description": "The AI's final response message in Markdown format. This is the complete answer to the original prompt, incorporating data from all executed queries.", + "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + }, + "omniChatUrl": { + "type": "string", + "format": "uri", + "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" + }, + "resultSummary": { + "type": "string", + "description": "Summary of the job result. Typically matches the final message content.", + "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + }, + "topic": { + "type": "string", + "description": "The topic name used for query generation.", + "example": "order_items" + } + }, + "additionalProperties": {} + }, + "AiJobAction": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "The AI's explanation of what it is doing in this step, written in natural language.", + "example": "I'll generate a query to find the top 5 products by total revenue." + }, + "result": { + "$ref": "#/components/schemas/AiJobActionQueryResult" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp when this action occurred.", + "example": "2025-01-15T10:00:10.000Z" + }, + "type": { + "type": "string", + "description": "The type of action. Common types include \"generate_query\" (query generation and execution) and \"summarize\" (final answer synthesis).", + "example": "generate_query" + } + }, + "required": [ + "message", + "timestamp", + "type" + ], + "additionalProperties": {} + }, + "AiJobActionQueryResult": { + "type": "object", + "properties": { + "csvResult": { + "type": "string", + "description": "Query results formatted as CSV text.", + "example": "Name,Total Revenue\nRay-Ban Sunglasses,\"678,994.41\"\nLevi's 501 Jeans,\"475,072.00\"" + }, + "csvResultWasTruncated": { + "type": "boolean", + "description": "Whether the CSV data was truncated due to size limits. If true, the full result set may contain additional rows not included in csvResult.", + "example": false + }, + "hasResults": { + "type": "boolean", + "description": "Whether the query returned any data rows.", + "example": true + }, + "query": { + "type": "object", + "additionalProperties": {}, + "description": "The semantic query definition that was executed. This can be used with the POST /api/v1/query/run endpoint to re-run the query." + }, + "queryName": { + "type": "string", + "description": "Human-readable name describing what this query retrieves.", + "example": "Top 5 Products by Revenue" + }, + "resultId": { + "type": "string", + "description": "Stable, unique identifier for this query result within the job. Use it to reference a specific result — for example, to correlate or de-duplicate results across responses.", + "example": "928c5838-000d-4943-b305-f6242c1b4922" + }, + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Whether the query executed successfully.", + "example": "success" + }, + "totalRowCount": { + "type": "integer", + "description": "Total number of rows returned by the query.", + "example": 5 + } + }, + "required": [ + "csvResult", + "csvResultWasTruncated", + "hasResults", + "query", + "queryName", + "status", + "totalRowCount" + ], + "description": "Query result data. Only present for generate_query action types." + }, + "ApiError422": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "No Arrow IPC data available for visualization" + } + }, + "required": [ + "error" + ] + }, + "AiBrandingResponse": { + "type": "object", + "properties": { + "body": { + "type": "string", + "description": "Body / description copy shown beneath the headline on AI helper landing surfaces.", + "example": "I can help answer data questions, build a Dashboard, or create an App." + }, + "headline": { + "type": "string", + "description": "Short headline shown on AI helper landing surfaces.", + "example": "What would you like to know?" + }, + "logoUrl": { + "type": [ + "string", + "null" + ], + "format": "uri", + "description": "Absolute URL to a custom AI helper logo. `null` when the org has not configured a custom logo — clients should render their default avatar (e.g. Blobby).", + "example": "https://example.com/blobby.png" + }, + "name": { + "type": "string", + "description": "Display name for the AI helper. Defaults to `Omni Agent` when no custom branding is set.", + "example": "Blobby" + }, + "placeholder": { + "type": "string", + "description": "Placeholder text for the AI helper's prompt input.", + "example": "Ask a question about your data..." + } + }, + "required": [ + "body", + "headline", + "logoUrl", + "name", + "placeholder" + ] + }, + "AiConversationsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiConversation" + }, + "description": "Conversations ordered by updatedAt descending." + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "PageInfo": { + "type": "object", + "properties": { + "hasNextPage": { + "type": "boolean", + "description": "Whether more results are available" + }, + "nextCursor": { + "type": [ + "string", + "null" + ], + "description": "Cursor for fetching the next page" + }, + "pageSize": { + "type": "number", + "description": "Number of results per page" + }, + "totalRecords": { + "type": "number", + "description": "Total number of records matching the query" + } + }, + "required": [ + "hasNextPage", + "nextCursor", + "pageSize", + "totalRecords" + ] + }, + "AiConversation": { + "type": "object", + "properties": { + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When the conversation was started.", + "example": "2025-01-15T10:00:00.000Z" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Conversation ID. Pass as conversationId on subsequent /api/v1/ai/jobs submissions to continue this conversation.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "lastPrompt": { + "type": [ + "string", + "null" + ], + "description": "The most recent user prompt in this conversation, useful for displaying a one-line summary in a list.", + "example": "What were our top products last week?" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Conversation title. Set by the AI after the first turn; null on brand-new sessions.", + "example": "Top products last week" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When the conversation was last touched (most recent prompt or AI activity).", + "example": "2025-01-15T10:01:30.000Z" + } + }, + "required": [ + "createdAt", + "id", + "lastPrompt", + "name", + "updatedAt" + ] + }, + "AiConversationDetailResponse": { + "type": "object", + "properties": { + "createdAt": { + "type": "string", + "format": "date-time" + }, + "id": { + "type": "string", + "format": "uuid" + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiConversationMessage" + }, + "description": "Messages in chronological order. Alternating user / assistant turns." + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "createdAt", + "id", + "messages", + "name", + "updatedAt" + ] + }, + "AiConversationMessage": { + "type": "object", + "properties": { + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When this turn was recorded.", + "example": "2025-01-15T10:00:00.000Z" + }, + "jobId": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "The agentic job that produced this assistant turn. Only set for assistant messages — clients use it to fetch the rendered chart via GET /api/v1/ai/jobs/{jobId}/vis. Null when the turn predates jobs or when we could not associate one.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "omniChatUrl": { + "type": [ + "string", + "null" + ], + "format": "uri", + "description": "Deep link to the assistant turn in the Omni chat UI. Null for user turns, and for assistant turns produced outside the Agentic API (where no AgenticJob row exists).", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" + }, + "role": { + "type": "string", + "enum": [ + "user", + "assistant" + ], + "description": "Speaker — `user` for prompts the user submitted, `assistant` for Blobby's responses.", + "example": "user" + }, + "text": { + "type": "string", + "description": "Markdown content of the message. For assistant turns this is the same string returned by /api/v1/ai/jobs/{jobId}/result#message.", + "example": "What were our top products last week?" + } + }, + "required": [ + "createdAt", + "jobId", + "omniChatUrl", + "role", + "text" + ] + }, + "AiCreditControlsResponse": { + "type": "object", + "properties": { + "accountCreditLimit": { + "type": "number", + "minimum": 0, + "description": "Monthly AI credit limit for the whole Omni account (shared across every org under the same Salesforce account), not just this org. 0 when no limit is configured.", + "example": 2000 + }, + "creditsUsed": { + "type": "number", + "minimum": 0, + "description": "This org's credit usage in the current billing period.", + "example": 450 + }, + "downgradeCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Downgrade threshold, or `null` if the downgrade control is off.", + "example": 800 + }, + "periodEnd": { + "type": "integer", + "minimum": 0, + "description": "End of the current billing period as a Unix ms timestamp (UTC calendar-month boundary)." + }, + "periodStart": { + "type": "integer", + "minimum": 0, + "description": "Start of the current billing period as a Unix ms timestamp (UTC calendar-month boundary)." + }, + "shutoffCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Shutoff threshold, or `null` if the shutoff control is off.", + "example": 1200 + }, + "userDefaultCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Default per-user AI credit limit, or `null` when users are unlimited by default.", + "example": 100 + } + }, + "required": [ + "accountCreditLimit", + "creditsUsed", + "downgradeCredits", + "periodEnd", + "periodStart", + "shutoffCredits", + "userDefaultCredits" + ] + }, + "AiCreditControlsUpdateBody": { + "type": "object", + "properties": { + "downgradeCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Credit usage at which AI downgrades to a cheaper model. Omit to leave unchanged, `null` to turn off, or a non-negative number to set. Must be at or below shutoffCredits.", + "example": 800 + }, + "shutoffCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Credit usage at which AI shuts off entirely. Omit to leave unchanged, `null` to turn off, or a non-negative number to set.", + "example": 1200 + }, + "userDefaultCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Default per-user AI credit limit for the billing period — what every user without an individual limit gets. Omit to leave unchanged, `null` for unlimited by default, or a non-negative number to set.", + "example": 100 + } + }, + "additionalProperties": false + }, + "AiCreditControlsUsersListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "creditLimit": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "The user's individual AI credit limit, or `null` for an explicit unlimited override.", + "example": 50 + }, + "userId": { + "type": "string", + "description": "The user's id within this organization.", + "example": "f4a2b3c8-0d1e-4f5a-9b6c-7d8e9f0a1b2c" + } + }, + "required": [ + "creditLimit", + "userId" + ] + }, + "description": "Users with an individual AI credit limit, ordered by userId ascending." + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "AiUserCreditLimitsResponse": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "type": "object", + "properties": { + "creditLimit": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "The user's effective AI credit limit, or `null` for unlimited.", + "example": 50 + }, + "userId": { + "type": "string", + "description": "The user's id within this organization.", + "example": "f4a2b3c8-0d1e-4f5a-9b6c-7d8e9f0a1b2c" + }, + "usesDefaultLimit": { + "type": "boolean", + "description": "True when the user has no individual limit and follows the org default." + } + }, + "required": [ + "creditLimit", + "userId", + "usesDefaultLimit" + ] + } + } + }, + "required": [ + "users" + ] + }, + "AiUserCreditLimitsUpdateBody": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiUserCreditLimitEntry" + }, + "minItems": 1, + "maxItems": 1000, + "description": "Users to update, at most 1000 per request. Each entry has a `userId` plus exactly one of `creditLimit` (number or `null`) or `useDefaultLimit: true`." + } + }, + "required": [ + "users" + ], + "additionalProperties": false + }, + "AiUserCreditLimitEntry": { + "type": "object", + "properties": { + "creditLimit": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "The user's individual AI credit limit for the billing period, or `null` for unlimited. Either way this overrides the org default. Mutually exclusive with `useDefaultLimit`.", + "example": 50 + }, + "useDefaultLimit": { + "type": "boolean", + "enum": [ + true + ], + "description": "Removes the user's individual limit so they follow the org default. Mutually exclusive with `creditLimit`." + }, + "userId": { + "type": "string", + "description": "The user's id within this organization.", + "example": "f4a2b3c8-0d1e-4f5a-9b6c-7d8e9f0a1b2c" + } + }, + "required": [ + "userId" + ], + "additionalProperties": false + }, + "RoutinesListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutineResponse" + }, + "description": "Routines returned for this request, newest first." + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "RoutineResponse": { + "type": "object", + "properties": { + "branchId": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Branch of the shared model the prompt runs against, or null." + }, + "createdAt": { + "type": "string", + "description": "ISO 8601 timestamp when the routine was created." + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Display-only notes about the routine, or null." + }, + "destination": { + "$ref": "#/components/schemas/RoutineDestinationResponse" + }, + "disabled": { + "type": "boolean", + "description": "Whether the owner has paused the routine." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the routine." + }, + "lastRun": { + "$ref": "#/components/schemas/RoutineLastRun" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The shared model the prompt runs against." + }, + "name": { + "type": "string", + "description": "Customer-visible name of the routine. Used as the email subject for email destinations, and shown on Slack deliveries." + }, + "prompt": { + "type": "string", + "description": "Natural language prompt Omni runs on each scheduled run." + }, + "recipientCount": { + "type": "integer", + "description": "Number of distinct deliverable recipients. For email, user groups are expanded to members and duplicates removed; a Slack routine is always 1 (its single channel or DM)." + }, + "schedule": { + "type": "string", + "description": "Six-field cron expression (minute, hour, day-of-month, month, day-of-week, year; use `?` for an unspecified day field)." + }, + "systemDisabled": { + "type": "boolean", + "description": "Whether Omni disabled the routine because it could no longer run successfully or safely." + }, + "systemDisabledReason": { + "type": [ + "string", + "null" + ], + "description": "Reason Omni disabled the routine, or null." + }, + "timezone": { + "type": "string", + "description": "IANA timezone identifier used to evaluate the schedule." + }, + "topicName": { + "type": [ + "string", + "null" + ], + "description": "Topic scoping query generation, or null." + }, + "updatedAt": { + "type": "string", + "description": "ISO 8601 timestamp when the routine was last updated." + } + }, + "required": [ + "branchId", + "createdAt", + "description", + "destination", + "disabled", + "id", + "lastRun", + "modelId", + "name", + "prompt", + "recipientCount", + "schedule", + "systemDisabled", + "systemDisabledReason", + "timezone", + "topicName", + "updatedAt" + ] + }, + "RoutineDestinationResponse": { + "oneOf": [ + { + "$ref": "#/components/schemas/RoutineEmailDestinationResponse" + }, + { + "$ref": "#/components/schemas/RoutineSlackDestination" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "email": "#/components/schemas/RoutineEmailDestinationResponse", + "slack": "#/components/schemas/RoutineSlackDestination" + } + }, + "description": "Delivery configuration for the routine." + }, + "RoutineEmailDestinationResponse": { + "type": "object", + "properties": { + "recipientEmails": { + "type": "array", + "items": { + "type": "string", + "format": "email" + }, + "description": "Email addresses configured as direct recipients of each scheduled run, resolved from their current membership.", + "example": [ + "alice@example.com", + "bob@example.com" + ] + }, + "type": { + "type": "string", + "enum": [ + "email" + ], + "description": "Selects email delivery — each scheduled run is sent to the listed email recipients and user groups.", + "example": "email" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "User group IDs whose active members receive each scheduled run. Omni expands each group to the members' current email addresses when the routine runs.", + "example": [ + "550e8400-e29b-41d4-a716-446655440000" + ] + } + }, + "required": [ + "recipientEmails", + "type", + "userGroupIds" + ], + "additionalProperties": false + }, + "RoutineSlackDestination": { + "type": "object", + "properties": { + "recipientId": { + "type": "string", + "minLength": 1, + "description": "The Slack channel ID (e.g. \"C01234567\") or user ID (e.g. \"U01234567\") that receives each scheduled run. Exactly one recipient per Slack routine.", + "example": "C01234567" + }, + "slackRecipientType": { + "type": "string", + "enum": [ + "channel", + "users" + ], + "description": "Whether `recipientId` is a Slack channel or a user (delivered as a direct message).", + "example": "channel" + }, + "type": { + "type": "string", + "enum": [ + "slack" + ], + "description": "Selects Slack delivery — each scheduled run is posted to one Slack channel or sent as a direct message to one user.", + "example": "slack" + } + }, + "required": [ + "recipientId", + "slackRecipientType", + "type" + ], + "additionalProperties": false + }, + "RoutineLastRun": { + "type": [ + "object", + "null" + ], + "properties": { + "completedAt": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp the last completed run finished." + }, + "label": { + "type": "string", + "description": "Customer-visible status of the last completed run.", + "example": "Delivered" + }, + "state": { + "type": "string", + "description": "Machine-readable status of the last completed run.", + "example": "COMPLETE" + } + }, + "required": [ + "completedAt", + "label", + "state" + ], + "description": "Most recent completed run, or null if the routine has never completed a run." + }, + "RoutineCreateResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique identifier for the newly created routine.", + "example": "880e8400-e29b-41d4-a716-446655440003" + } + }, + "required": [ + "id" + ] + }, + "ApiError429": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "User has reached the maximum of 100 routines" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 429 + } + }, + "required": [ + "detail", + "status" + ] + }, + "RoutineCreateBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "description": { + "type": "string", + "maxLength": 2000, + "description": "Optional human-readable notes about the routine. Display-only — never used as model input.", + "example": "Weekly signups summary for the growth team." + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The UUID of the shared model the prompt runs against. Only shared models are supported.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 512, + "description": "Customer-visible name of the routine. Used as the email subject for email destinations, and shown on Slack deliveries.", + "example": "Weekly user signups" + }, + "prompt": { + "type": "string", + "minLength": 1, + "description": "Natural language prompt Omni runs on each scheduled run.", + "example": "How many users signed up last week?" + }, + "schedule": { + "type": "string", + "minLength": 1, + "description": "Six-field cron expression (minute, hour, day-of-month, month, day-of-week, year; use `?` for an unspecified day field). Minimum frequency is once per hour; contact Omni support if you need more frequent scheduling.", + "example": "0 9 ? * MON *" + }, + "timezone": { + "type": "string", + "minLength": 1, + "description": "IANA timezone identifier used to evaluate the schedule.", + "example": "America/New_York" + }, + "topicName": { + "type": "string", + "maxLength": 256, + "description": "Topic name to scope query generation. If omitted, the AI picks the best topic.", + "example": "users" + }, + "destination": { + "$ref": "#/components/schemas/RoutineDestination" + } + }, + "required": [ + "modelId", + "name", + "prompt", + "schedule", + "timezone", + "destination" + ], + "additionalProperties": false + }, + "RoutineDestination": { + "oneOf": [ + { + "$ref": "#/components/schemas/RoutineEmailDestination" + }, + { + "$ref": "#/components/schemas/RoutineSlackDestination" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "email": "#/components/schemas/RoutineEmailDestination", + "slack": "#/components/schemas/RoutineSlackDestination" + } + }, + "description": "Single delivery destination for the routine. To send results to multiple destinations, create one routine per destination. Omni runs the prompt once per scheduled run using the routine owner's permissions, and every recipient receives the same result regardless of their own permissions." + }, + "RoutineEmailDestination": { + "type": "object", + "properties": { + "recipientEmails": { + "type": "array", + "items": { + "type": "string", + "format": "email" + }, + "maxItems": 100, + "default": [], + "description": "Email addresses that receive each scheduled run of the routine.", + "example": [ + "alice@example.com", + "bob@example.com" + ] + }, + "type": { + "type": "string", + "enum": [ + "email" + ], + "description": "Selects email delivery — each scheduled run is sent to the listed email recipients and user groups.", + "example": "email" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "maxItems": 100, + "default": [], + "description": "User group IDs whose active members receive each scheduled run. Omni expands each group to the members' current email addresses when the routine runs.", + "example": [ + "550e8400-e29b-41d4-a716-446655440000" + ] + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + "RoutineUpdateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 2000, + "description": "Display-only notes about the routine. Pass null to clear it." + }, + "destination": { + "allOf": [ + { + "$ref": "#/components/schemas/RoutineDestination" + }, + { + "description": "Replaces the routine's full recipient configuration with the supplied destination." + } + ] + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 512, + "description": "New customer-visible name of the routine. Used as the email subject for email destinations, and shown on Slack deliveries." + }, + "prompt": { + "type": "string", + "minLength": 1, + "description": "New natural language prompt Omni runs on each scheduled run." + }, + "schedule": { + "type": "string", + "minLength": 1, + "description": "New six-field cron expression (minute, hour, day-of-month, month, day-of-week, year; use `?` for an unspecified day field). Minimum frequency is once per hour." + }, + "timezone": { + "type": "string", + "minLength": 1, + "description": "New IANA timezone identifier used to evaluate the schedule." + } + }, + "additionalProperties": false + }, + "RoutineDeleteResponse": { + "type": "object", + "properties": { + "deleted": { + "type": "boolean", + "enum": [ + true + ], + "description": "Always true on a successful delete." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The deleted routine’s ID." + } + }, + "required": [ + "deleted", + "id" + ] + }, + "RoutineTriggerResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The ID of the run (scheduled job) that was started.", + "example": "990e8400-e29b-41d4-a716-446655440004" + } + }, + "required": [ + "id" + ] + }, + "ApiKeyListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApiKey" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "ApiKey": { + "type": "object", + "properties": { + "createdAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of when the token was created", + "example": "2026-01-15T10:00:00.000Z" + }, + "enabled": { + "type": "boolean", + "description": "Whether the token can currently authenticate. A disabled token cannot authenticate but remains visible until deleted.", + "example": true + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the token", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "membershipId": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Membership ID of the user the token is scoped to. Null for organization-level tokens.", + "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" + }, + "name": { + "type": "string", + "description": "Human-readable name for the token", + "example": "CI deployment key" + }, + "type": { + "type": "string", + "enum": [ + "organization", + "personal", + "mcp" + ], + "description": "Token type: `organization` (org-level), `personal` (user-created personal access token), or `mcp` (MCP OAuth grant).", + "example": "organization" + } + }, + "required": [ + "createdAt", + "enabled", + "id", + "membershipId", + "name", + "type" + ] + }, + "ApiKeyUpdateBody": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Set to `false` to disable the token, `true` to re-enable it.", + "example": false + } + }, + "required": [ + "enabled" + ], + "additionalProperties": false + }, + "ApiKeyDeleteResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Human-readable description of the outcome", + "example": "API token revoked" + }, + "success": { + "type": "boolean", + "enum": [ + true + ], + "description": "Always `true` on a successful revocation" + } + }, + "required": [ + "message", + "success" + ] + }, + "DbtEnvironmentListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtEnvironmentItem" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "DbtEnvironmentItem": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique environment identifier" + }, + "isDefaultEnvironment": { + "type": "boolean", + "description": "Whether this is the default environment" + }, + "isDeferralEnabled": { + "type": "boolean", + "description": "Whether dbt deferral is enabled for this environment. Always false for the default (production) environment — the backend rejects enabling it there." + }, + "name": { + "type": "string", + "description": "Environment name" + }, + "ownerId": { + "type": [ + "string", + "null" + ], + "description": "User ID of the environment owner, or null if not a personal environment" + }, + "targetDatabase": { + "type": [ + "string", + "null" + ], + "description": "Target database override" + }, + "targetName": { + "type": [ + "string", + "null" + ], + "description": "Target name override" + }, + "targetRole": { + "type": [ + "string", + "null" + ], + "description": "Target role override" + }, + "targetSchema": { + "type": "string", + "description": "Target schema" + }, + "variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtEnvironmentResponseVariable" + }, + "description": "Environment variables" + } + }, + "required": [ + "id", + "isDefaultEnvironment", + "isDeferralEnabled", + "name", + "ownerId", + "targetDatabase", + "targetName", + "targetRole", + "targetSchema", + "variables" + ] + }, + "DbtEnvironmentResponseVariable": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Variable ID" + }, + "isSecret": { + "type": "boolean", + "description": "Whether the variable value is secret" + }, + "name": { + "type": "string", + "description": "Variable name" + }, + "value": { + "type": [ + "string", + "null" + ], + "description": "Variable value (null for secret variables)" + } + }, + "required": [ + "id", + "isSecret", + "name", + "value" + ] + }, + "DbtEnvironmentCreateBody": { + "type": "object", + "properties": { + "isDeferralEnabled": { + "type": "boolean", + "default": false, + "description": "Whether to enable dbt deferral for this environment. Ignored (forced to false) for the default (production) environment.", + "example": false + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Environment name", + "example": "PR_1111_Expose" + }, + "ownerId": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", + "example": null + }, + "targetDatabase": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target database override", + "example": "analytics_dev" + }, + "targetName": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target name override", + "example": null + }, + "targetRole": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target role override", + "example": null + }, + "targetSchema": { + "type": "string", + "minLength": 1, + "description": "Target schema for this environment", + "example": "PR_1111_Expose" + }, + "variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtEnvironmentVariable" + }, + "default": [], + "description": "Environment variables" + } + }, + "required": [ + "name", + "targetSchema" + ] + }, + "DbtEnvironmentVariable": { + "type": "object", + "properties": { + "isSecret": { + "type": "boolean", + "description": "Whether the variable value is secret" + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Variable name" + }, + "value": { + "type": "string", + "description": "Variable value" + } + }, + "required": [ + "isSecret", + "name", + "value" + ] + }, + "DbtEnvironmentUpdateBody": { + "type": "object", + "properties": { + "isDeferralEnabled": { + "type": "boolean", + "default": false, + "description": "Whether to enable dbt deferral for this environment. Ignored (forced to false) for the default (production) environment.", + "example": false + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Environment name", + "example": "PR_1111_Expose" + }, + "ownerId": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", + "example": null + }, + "targetDatabase": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target database override", + "example": "analytics_dev" + }, + "targetName": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target name override", + "example": null + }, + "targetRole": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target role override", + "example": null + }, + "targetSchema": { + "type": "string", + "minLength": 1, + "description": "Target schema for this environment", + "example": "PR_1111_Expose" + }, + "variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtEnvironmentVariableUpdateOrNew" + }, + "default": [], + "description": "Environment variables. Variables with an id update existing ones; variables without an id create new ones." + } + }, + "required": [ + "name", + "targetSchema" + ] + }, + "DbtEnvironmentVariableUpdateOrNew": { + "oneOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentVariableUpdate" + }, + { + "$ref": "#/components/schemas/DbtEnvironmentVariable" + } + ] + }, + "DbtEnvironmentDeleteResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Confirmation message", + "example": "dbt environment deleted successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the deletion was successful", + "example": true + } + }, + "required": [ + "message", + "success" + ] + }, + "ContentListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/ApiDocument" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "document" + ] + } + }, + "required": [ + "type" + ] + } + ] + }, + { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Content name" + }, + "owner": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "User ID of the owner" + }, + "name": { + "type": "string", + "description": "Name of the owner" + } + }, + "required": [ + "id", + "name" + ], + "description": "Content owner" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Content access scope" + }, + "_count": { + "type": "object", + "properties": { + "documents": { + "type": "number", + "description": "Number of documents" + }, + "favorites": { + "type": "number", + "description": "Number of users who favorited" + } + }, + "required": [ + "documents", + "favorites" + ], + "description": "Folder counts" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels" + }, + "path": { + "type": "string", + "description": "Full path to the folder", + "example": "sales-reports/q1-2026" + }, + "url": { + "type": "string", + "description": "URL to view the folder in the Omni UI.", + "example": "https://org.omni.co/f/sales-reports" + }, + "type": { + "type": "string", + "enum": [ + "folder" + ] + } + }, + "required": [ + "id", + "name", + "owner", + "scope", + "path", + "url", + "type" + ] + } + ] + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "OwnerInternal": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Owner membership ID" + }, + "name": { + "type": "string", + "description": "Owner display name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Content owner" + }, + "ContentShareScope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Content access scope" + }, + "InternalFolder": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "description": "Folder ID" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Folder name" + }, + "path": { + "type": "string", + "description": "Folder path" + }, + "scope": { + "allOf": [ + { + "$ref": "#/components/schemas/ContentShareScope" + }, + { + "description": "Folder access scope" + } + ] + } + }, + "required": [ + "id", + "name", + "path", + "scope" + ], + "description": "Parent folder" + }, + "ApiDocument": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Content name" + }, + "owner": { + "$ref": "#/components/schemas/OwnerInternal" + }, + "scope": { + "$ref": "#/components/schemas/ContentShareScope" + }, + "_count": { + "type": "object", + "properties": { + "favorites": { + "type": "number", + "description": "Number of users who favorited" + }, + "views": { + "type": "number", + "description": "Number of views" + } + }, + "required": [ + "favorites", + "views" + ], + "description": "Document counts" + }, + "connectionId": { + "type": "string", + "description": "Connection ID" + }, + "deleted": { + "type": "boolean", + "description": "Whether document is deleted" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "folder": { + "$ref": "#/components/schemas/InternalFolder" + }, + "hasApp": { + "type": "boolean", + "description": "Whether document has an app" + }, + "hasDashboard": { + "type": "boolean", + "description": "Whether document has a dashboard" + }, + "identifier": { + "type": "string", + "description": "Document identifier" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Applied labels" + }, + "lastViewedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Last time the dashboard was viewed" + }, + "updatedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Last updated timestamp" + }, + "url": { + "type": "string", + "description": "URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an app, otherwise the workbook URL.", + "example": "https://org.omni.co/dashboards/abc123" + }, + "visits": { + "type": [ + "number", + "null" + ], + "description": "Number of dashboard visits" + } + }, + "required": [ + "name", + "owner", + "scope", + "connectionId", + "deleted", + "folder", + "hasApp", + "hasDashboard", + "identifier", + "updatedAt", + "url" + ] + }, + "DashboardsDownloadResponse": { + "type": "object", + "properties": { + "job_id": { + "type": "string", + "format": "uuid", + "description": "ID of the download job. Use this to poll for download status.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "message": { + "type": "string", + "description": "Status message", + "example": "Download initiated successfully" + } + }, + "required": [ + "job_id", + "message" + ] + }, + "DashboardsDownloadBody": { + "type": "object", + "properties": { + "enableFormatting": { + "type": "boolean", + "default": false, + "description": "Compatible with csv, xlsx & json formats. If true, formatting will be enabled in the output. Note: If true for json format, a queryIdentifierMapKey is required.", + "example": false + }, + "expandTablesToShowAllRows": { + "type": "boolean", + "description": "Compatible with pdf and png formats. If true, up to 1,000 rows in table visualizations will be included in the delivery. Note: This parameter cannot be used when paperFormat: fit_page.", + "example": false + }, + "filterConfig": { + "description": "An object specifying the filter conditions to apply to the task. The filter key specified must already exist in the dashboard.", + "example": { + "status": [ + "active", + "pending" + ] + } + }, + "format": { + "type": "string", + "enum": [ + "pdf", + "png", + "csv", + "xlsx", + "json" + ], + "description": "Output format for the download: pdf, png, csv, xlsx, or json", + "example": "pdf" + }, + "hideHiddenFields": { + "type": "boolean", + "default": false, + "description": "Compatible with csv & xlsx formats. If true, fields marked as hidden won't be displayed in the output.", + "example": false + }, + "hideTitle": { + "type": "boolean", + "default": false, + "description": "Compatible with pdf & png formats. If true, the content's title will be hidden in the output.", + "example": false + }, + "maxRowLimit": { + "type": "number", + "minimum": 1, + "description": "Compatible with csv, json, & xlsx formats. Used with overrideRowLimit. Specifies the maximum number of rows.", + "example": 1000 + }, + "overrideRowLimit": { + "type": "boolean", + "default": false, + "description": "Compatible with csv, json, & xlsx formats. If true, the default row limit will be overridden. Note: If true for json and xlsx formats, a queryIdentifierMapKey is required.", + "example": false + }, + "paperFormat": { + "type": "string", + "enum": [ + "a3", + "a4", + "fit_page", + "legal", + "letter", + "tabloid" + ], + "description": "Compatible with pdf formats. Defines the paper format (size) of the resulting PDF. Must be one of: a3, a4, letter, legal, fit_page, tabloid.", + "example": "letter" + }, + "paperOrientation": { + "type": "string", + "enum": [ + "portrait", + "landscape" + ], + "description": "Compatible with pdf formats. Defines the paper orientation of the resulting PDF. Must be one of: portrait, landscape.", + "example": "landscape" + }, + "queryIdentifierMapKey": { + "type": "string", + "description": "Required for single tile tasks. The ID of the query to include in a single tile task. Must reference a valid query in the dashboard.", + "example": "Jmn2r3KV" + }, + "showContentLink": { + "type": "boolean", + "default": true, + "description": "Compatible with all formats except link_only. If true, a link to the content will be shown in the output.", + "example": true + }, + "showFilters": { + "type": "boolean", + "default": true, + "description": "Compatible with all formats except link_only & csv. If true, filters will be shown in the output.", + "example": true + }, + "singleColumnLayout": { + "type": "boolean", + "description": "Compatible with pdf and png formats. If true, dashboard tiles will be arranged into a single vertical column.", + "example": false + }, + "useCache": { + "type": "boolean", + "default": false, + "description": "If true, allow scheduled queries to use cached results instead of always running fresh queries.", + "example": false + }, + "filename": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Custom filename for the downloaded file (without extension)", + "example": "monthly-report" + } + }, + "required": [ + "format" + ], + "additionalProperties": false + }, + "DashboardFiltersResponse": { + "type": "object", + "properties": { + "controls": { + "description": "Control configuration object. Keys are control IDs, values contain controlType, filterId, label, etc." + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of filter IDs defining display order", + "example": [ + "filter_abc123", + "filter_def456" + ] + }, + "filters": { + "description": "Filter configuration object. Keys are filter IDs, values contain fieldName, viewName, kind, defaultValue, etc." + }, + "identifier": { + "type": "string", + "description": "Dashboard identifier", + "example": "12db1a0a" + } + }, + "required": [ + "filterOrder", + "identifier" + ] + }, + "DashboardsUpdateFiltersBody": { + "type": "object", + "properties": { + "clearExistingDraft": { + "type": "boolean", + "default": false, + "description": "When true, discards any existing draft before applying updates. Required when updating a published document that already has a draft." + }, + "controls": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": {}, + "additionalProperties": {} + }, + "description": "Partial control updates. Keys are control IDs that must exist in the dashboard." + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "New order for filters. All filter IDs must exist in the dashboard." + }, + "filters": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": {}, + "additionalProperties": {} + }, + "description": "Partial filter updates. Keys are filter IDs that must exist in the dashboard." + } + } + }, + "DocumentsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Document" + }, + "description": "List of documents" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "Document": { + "type": "object", + "properties": { + "_count": { + "type": "object", + "properties": { + "favorites": { + "type": "number", + "description": "Number of users who favorited this document" + }, + "views": { + "type": "number", + "description": "Number of views" + } + }, + "required": [ + "favorites", + "views" + ], + "description": "Document counts (included when _count is in include param)" + }, + "connectionId": { + "type": "string", + "description": "Connection ID the document is associated with" + }, + "deleted": { + "type": "boolean", + "description": "Whether the document is deleted (archived)" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "folder": { + "$ref": "#/components/schemas/DocumentFolder" + }, + "hasApp": { + "type": "boolean", + "description": "Whether the document has an associated app" + }, + "hasDashboard": { + "type": "boolean", + "description": "Whether the document has an associated dashboard" + }, + "identifier": { + "type": "string", + "description": "Document identifier", + "example": "abc123" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels applied to the document (included when labels is in include param)" + }, + "name": { + "type": "string", + "description": "Document name" + }, + "owner": { + "$ref": "#/components/schemas/DocumentOwner" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Document access scope" + }, + "type": { + "type": "string", + "enum": [ + "document" + ], + "description": "Content type" + }, + "updatedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Last updated timestamp" + }, + "url": { + "type": "string", + "description": "URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an app, otherwise the workbook URL.", + "example": "https://org.omni.co/dashboards/abc123" + } + }, + "required": [ + "connectionId", + "deleted", + "folder", + "hasDashboard", + "identifier", + "name", + "owner", + "scope", + "type", + "updatedAt", + "url" + ] + }, + "DocumentFolder": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "description": "Folder ID" + }, + "name": { + "type": "string", + "description": "Folder name" + }, + "path": { + "type": "string", + "description": "Folder path" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Folder access scope" + } + }, + "required": [ + "id", + "name", + "path", + "scope" + ], + "description": "Folder containing the document" + }, + "DocumentOwner": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Owner membership ID" + }, + "name": { + "type": "string", + "description": "Owner display name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Document owner" + }, + "DocumentsCreateResponse": { + "type": "object", + "properties": { + "dashboard": { + "type": "object", + "properties": { + "dashboardId": { + "type": "string", + "description": "Dashboard ID" + }, + "id": { + "type": "string", + "description": "Dashboard ID" + } + }, + "required": [ + "dashboardId", + "id" + ], + "additionalProperties": {}, + "description": "Created dashboard" + }, + "workbook": { + "type": "object", + "properties": { + "documentId": { + "type": "string", + "description": "Document ID (deprecated)" + }, + "id": { + "type": "string", + "description": "Workbook ID" + } + }, + "required": [ + "documentId", + "id" + ], + "additionalProperties": {}, + "description": "Created workbook" + } + }, + "required": [ + "dashboard", + "workbook" + ] + }, + "DocumentsCreateBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID to associate the document with a model branch", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "facetFilters": { + "type": "boolean", + "description": "Enable facet filters on the dashboard" + }, + "filterConfig": { + "description": "Dashboard filter configuration" + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Order of filters in the dashboard" + }, + "identifier": { + "$ref": "#/components/schemas/DocumentIdentifier" + }, + "metadata": { + "description": "Dashboard metadata" + }, + "metadataVersion": { + "type": "string", + "description": "Dashboard metadata version (required when metadata is provided)" + }, + "modelId": { + "type": "string", + "description": "Shared model ID to base the document on" + }, + "name": { + "type": "string", + "description": "Document name" + }, + "queryPresentations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "aiConfig": { + "description": "AI configuration" + }, + "chartType": { + "type": [ + "string", + "null" + ], + "description": "Chart type" + }, + "description": { + "type": "string", + "maxLength": 500, + "description": "Query presentation description" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 144, + "description": "Query presentation name" + }, + "prefersChart": { + "type": "boolean", + "description": "Whether to prefer chart view" + }, + "query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Query fields" + }, + "table": { + "type": "string", + "description": "Query table/topic" + } + }, + "required": [ + "fields", + "table" + ], + "additionalProperties": {}, + "description": "Query definition" + }, + "resultConfig": { + "description": "Result configuration" + }, + "subTitle": { + "type": "string", + "maxLength": 250, + "description": "Subtitle" + }, + "topicName": { + "type": [ + "string", + "null" + ], + "maxLength": 256, + "description": "Topic name. Omit or pass null for raw-SQL tiles or any tile with no semantic topic." + }, + "visConfig": { + "$ref": "#/components/schemas/ApiVisConfig" + } + }, + "required": [ + "name", + "query" + ] + }, + "description": "Query presentations for the document" + } + }, + "required": [ + "modelId", + "name" + ] + }, + "DocumentIdentifier": { + "type": "string", + "minLength": 2, + "maxLength": 48, + "description": "Optional document identifier. If omitted, an identifier is auto-generated. Must be unique within the organization." + }, + "ApiVisConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "config": { + "type": "object", + "additionalProperties": {}, + "description": "Visualization spec (chart configuration)" + }, + "fields": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string", + "minLength": 1 + }, + "description": "Field names used in the visualization" + }, + "visType": { + "type": "string", + "enum": [ + "vegalite", + "omni-ai-summary-markdown", + "basic", + "omni-kpi", + "map", + "omni-markdown", + "funnel", + "sankey", + "single-record", + "svg-map", + "treemap", + "omni-spreadsheet", + "spreadsheet-tab", + "summary-value", + "omni-table" + ], + "description": "Visualization type (e.g. basic, omni-markdown, omni-table)" + } + }, + "additionalProperties": {}, + "description": "Visualization configuration" + }, + "DocumentsGetResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "documentMetadata": { + "description": "Document metadata" + }, + "facetFilters": { + "type": "boolean", + "description": "Whether facet filters are enabled" + }, + "filterConfig": { + "description": "Dashboard filter configuration" + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Order of filters" + }, + "modelId": { + "type": "string", + "description": "Model ID" + }, + "name": { + "type": "string", + "description": "Document name" + }, + "queryPresentations": { + "type": "array", + "items": {}, + "description": "Query presentations" + }, + "refreshInterval": { + "type": [ + "number", + "null" + ], + "description": "Auto-refresh interval in seconds" + } + }, + "required": [ + "facetFilters", + "filterOrder", + "modelId", + "name", + "queryPresentations", + "refreshInterval" + ] + }, + "DocumentsPutResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "identifier": { + "type": "string", + "description": "Document identifier" + }, + "name": { + "type": "string", + "description": "Updated document name" + } + }, + "required": [ + "identifier", + "name" + ] + }, + "DocumentsPutBody": { + "type": "object", + "properties": { + "clearExistingDraft": { + "type": "boolean", + "default": false, + "description": "Clear existing draft before updating (for published documents with drafts)" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "documentMetadata": { + "description": "Document presentation metadata" + }, + "facetFilters": { + "type": "boolean", + "description": "Enable facet filters" + }, + "filterConfig": { + "description": "Filter configuration" + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Order of filters" + }, + "modelId": { + "type": "string", + "description": "Model ID" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 254, + "description": "Document name" + }, + "queryPresentations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DocumentsPutQueryPresentation" + }, + "minItems": 1, + "description": "Query presentations (full replacement)" + }, + "refreshInterval": { + "type": [ + "integer", + "null" + ], + "minimum": 60, + "description": "Auto-refresh interval in seconds" + } + }, + "required": [ + "facetFilters", + "filterOrder", + "modelId", + "name", + "queryPresentations", + "refreshInterval" + ] + }, + "DocumentsPutQueryPresentation": { + "type": "object", + "properties": { + "aiConfig": { + "type": "object", + "properties": { + "description": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + }, + "subTitle": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + } + }, + "description": "AI configuration" + }, + "chartType": { + "type": [ + "string", + "null" + ], + "enum": [ + "auto", + "area", + "areaStacked", + "areaStackedPercentage", + "bar", + "barLine", + "barGrouped", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "regionMap", + "markdown", + "omni-ai-summary-markdown", + "pie", + "funnel", + "sankey", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "singleRecord", + "omni-spreadsheet", + "summaryValue", + "svgMap", + "table", + "treemap", + null + ], + "description": "Chart type" + }, + "description": { + "type": "string", + "maxLength": 500, + "description": "Description" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 144, + "description": "Query presentation name" + }, + "prefersChart": { + "type": "boolean", + "description": "Whether to prefer chart view" + }, + "query": { + "description": "Query definition" + }, + "queryIdentifierMapKey": { + "type": "string", + "pattern": "^[1-9][0-9]*$", + "description": "Round-trip preservation hint. When the value matches an existing key on the document, the tile keeps its map key (and dashboard containers stay attached). Omit for new tiles. Must be a positive integer string (e.g. \"1\", \"2\", \"10\")." + }, + "resultConfig": { + "description": "Result config" + }, + "subTitle": { + "type": "string", + "maxLength": 250, + "description": "Subtitle" + }, + "topicName": { + "type": [ + "string", + "null" + ], + "maxLength": 256, + "description": "Topic name. Omit or pass null for raw-SQL tiles or any tile with no semantic topic." + }, + "visConfig": { + "$ref": "#/components/schemas/ApiVisConfig" + } + }, + "required": [ + "name" + ] + }, + "DocumentsUpdateResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "identifier": { + "type": "string", + "description": "Document identifier" + }, + "name": { + "type": "string", + "description": "Updated document name" + } + }, + "required": [ + "identifier", + "name" + ] + }, + "DocumentsUpdateBody": { + "type": "object", + "properties": { + "clearExistingDraft": { + "type": "boolean", + "default": false, + "description": "Clear existing draft before updating (for published documents with drafts)" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "identifier": { + "allOf": [ + { + "$ref": "#/components/schemas/DocumentIdentifier" + }, + { + "description": "New identifier for the document. Must be unique within the organization. The previous identifier is retained in the document identifier history and continues to redirect." + } + ] + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 254, + "description": "New document name" + } + } + }, + "SuccessResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation was successful", + "example": true + } + }, + "required": [ + "success" + ] + }, + "DocumentsGetQueriesResponse": { + "type": "object", + "properties": { + "queries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Query presentation ID" + }, + "name": { + "type": "string", + "description": "Query presentation name" + }, + "query": { + "description": "Query JSON definition" + }, + "queryIdentifierMapKey": { + "type": "string", + "description": "Key in the query identifier map" + }, + "url": { + "type": "string", + "description": "URL to view this specific query/sheet in the workbook.", + "example": "https://org.omni.co/w/abc123?key=1" + } + }, + "required": [ + "id", + "name", + "queryIdentifierMapKey", + "url" + ] + }, + "description": "List of queries in the document" + } + }, + "required": [ + "queries" + ] + }, + "DocumentsMoveBody": { + "type": "object", + "properties": { + "folderPath": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Destination folder path (null for root)" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Access scope for the document" + } + }, + "required": [ + "folderPath" + ] + }, + "DocumentsGetPermissionsResponse": { + "type": "object", + "properties": { + "permits": { + "description": "User permits for the document" + } + } + }, + "DocumentsUpdatePermissionSettingsBody": { + "type": "object", + "properties": { + "canDownload": { + "type": "boolean", + "description": "Allow downloading" + }, + "canDrill": { + "type": "boolean", + "description": "Allow drill-down" + }, + "canSchedule": { + "type": "boolean", + "description": "Allow scheduling" + }, + "canUpload": { + "type": "boolean", + "description": "Allow uploads" + }, + "canUseDashboardAi": { + "type": "boolean", + "description": "Allow using dashboard AI" + }, + "canUseTimezoneOverride": { + "type": "boolean", + "description": "Allow timezone override" + }, + "canViewWorkbook": { + "type": "boolean", + "description": "Allow viewing workbook" + }, + "organizationAccessBoost": { + "type": "boolean", + "description": "Boost organization access" + }, + "organizationRole": { + "type": "string", + "enum": [ + "viewer", + "editor", + "manager", + "no_access" + ], + "description": "Organization-wide role for the document" + }, + "requirePullRequestToPublish": { + "type": "boolean", + "description": "Require pull request to publish changes" + } + } + }, + "DocumentsAddPermitsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "default": false, + "description": "Grant access boost" + }, + "role": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "Role to grant" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to grant access to" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User membership IDs to grant access to" + } + }, + "required": [ + "role" + ] + }, + "DocumentsUpdatePermitsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "description": "Access boost setting" + }, + "role": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "Role to set" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to update" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User membership IDs to update" + } + } + }, + "DocumentsRevokePermitsBody": { + "type": "object", + "properties": { + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to revoke access from" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User membership IDs to revoke access from" + } + } + }, + "DocumentsCreateDraftResponse": { + "type": "object", + "properties": { + "identifier": { + "type": "string", + "description": "Draft document identifier" + } + }, + "required": [ + "identifier" + ] + }, + "DocumentsCreateDraftBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Branch ID for the draft" + } + } + }, + "DocumentsDiscardDraftResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message" + } + }, + "required": [ + "message" + ] + }, + "DocumentsDiscardDraftBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Branch ID for the draft" + } + } + }, + "DocumentsListDraftsResponse": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApiDraft" + } + }, + "ApiDraft": { + "type": "object", + "properties": { + "branch": { + "$ref": "#/components/schemas/ApiDraftBranch" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When the draft was created" + }, + "createdBy": { + "$ref": "#/components/schemas/ApiDraftActor" + }, + "draftOutOfDate": { + "type": "boolean", + "description": "True when the published document was published more recently than the draft was created (the draft is based on a stale baseline)" + }, + "identifier": { + "type": "string", + "description": "Draft workbook identifier — use this to address the draft" + }, + "lastEditedBy": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiDraftActor" + }, + { + "description": "User who most recently edited the draft" + } + ] + }, + "publishedIdentifier": { + "type": "string", + "description": "Identifier of the published document the draft is for" + }, + "status": { + "$ref": "#/components/schemas/ApiDraftStatus" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "Most recent edit time on the draft workbook" + }, + "workbookModelId": { + "type": "string", + "format": "uuid", + "description": "omni_model ID for the draft workbook" + } + }, + "required": [ + "branch", + "createdAt", + "createdBy", + "draftOutOfDate", + "identifier", + "lastEditedBy", + "publishedIdentifier", + "status", + "updatedAt", + "workbookModelId" + ] + }, + "ApiDraftBranch": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Branch (omni model) ID" + }, + "name": { + "type": "string", + "description": "Branch name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Branch the draft is attached to, or null for a draft on main" + }, + "ApiDraftActor": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Display name" + } + }, + "required": [ + "name" + ], + "description": "User who created the draft" + }, + "ApiDraftStatus": { + "type": "string", + "enum": [ + "active", + "archived" + ], + "description": "Lifecycle status: \"active\" for current drafts, \"archived\" for soft-deleted drafts (retained ~7 days)" + }, + "DocumentsDuplicateResponse": { + "type": "object", + "properties": { + "dashboardId": { + "type": "string", + "description": "New dashboard ID" + }, + "identifier": { + "type": "string", + "description": "New document identifier" + }, + "name": { + "type": "string", + "description": "Document name" + }, + "workbookId": { + "type": "string", + "description": "New workbook ID" + } + }, + "required": [ + "dashboardId", + "identifier", + "name", + "workbookId" + ] + }, + "DocumentsDuplicateBody": { + "type": "object", + "properties": { + "folderPath": { + "type": [ + "string", + "null" + ], + "description": "Destination folder path (null for root)" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 254, + "description": "Name for the duplicated document" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Access scope for the duplicated document" + } + }, + "required": [ + "name" + ] + }, + "DocumentsUpgradeLayoutResponse": { + "type": "object", + "properties": { + "identifier": { + "type": "string", + "description": "Document identifier" + }, + "upgraded": { + "type": "boolean", + "description": "True when the layout was upgraded, false when the document already had advanced layout (no-op)." + } + }, + "required": [ + "identifier", + "upgraded" + ] + }, + "DocumentsUpgradeLayoutBody": { + "type": "object", + "properties": { + "clearExistingDraft": { + "type": "boolean", + "default": false, + "description": "When upgrading a published document, discard any existing draft instead of failing with a conflict." + } + } + }, + "DocumentsBulkUpdateLabelsResponse": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Updated list of labels on the document" + } + }, + "required": [ + "labels" + ] + }, + "DocumentsBulkUpdateLabelsBody": { + "type": "object", + "properties": { + "add": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "Labels to add" + }, + "remove": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "Labels to remove" + } + } + }, + "DocumentsTransferOwnershipBody": { + "type": "object", + "properties": { + "userId": { + "type": "string", + "format": "uuid", + "description": "Membership ID of the new owner" + } + }, + "required": [ + "userId" + ] + }, + "DocumentsAccessListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "principals": { + "type": "array", + "items": {}, + "description": "List of users and groups with access" + } + }, + "required": [ + "pageInfo", + "principals" + ] + }, + "DocumentsListFavoritesResponse": { + "type": "object", + "properties": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DocumentFavoriteUser" + }, + "description": "Users who favorited this document" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "DocumentFavoriteUser": { + "type": "object", + "properties": { + "email": { + "type": [ + "string", + "null" + ], + "description": "Favoriting user's email. Null when the user has no resolvable email — e.g. an embed-SSO favoriter whose embed session did not provide one." + }, + "favoritedAt": { + "type": "string", + "description": "ISO 8601 timestamp when the user favorited the document" + }, + "name": { + "type": "string", + "description": "Favoriting user's display name" + }, + "userId": { + "type": "string", + "description": "Membership ID of the user who favorited the document (use with other v1 endpoints' userId parameter)" + } + }, + "required": [ + "email", + "favoritedAt", + "name", + "userId" + ] + }, + "DocumentsV2CreateResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "identifier": { + "type": "string", + "description": "Identifier of the newly created document." + }, + "name": { + "type": "string", + "description": "Document name." + } + }, + "required": [ + "description", + "identifier", + "name" + ] + }, + "DocumentsV2CreateBody": { + "type": "object", + "properties": { + "containers": { + "$ref": "#/components/schemas/ContainersOnCreate" + }, + "controls": { + "$ref": "#/components/schemas/ControlsPatchExternal" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "folderId": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Folder to create the document in. When omitted, defaults to the caller’s personal \"My documents\" (requires permission to save personal content — otherwise the request is rejected)." + }, + "identifier": { + "allOf": [ + { + "$ref": "#/components/schemas/DocumentIdentifier" + }, + { + "description": "Identifier for the new document. Must be unique within the organization. Auto-generated when omitted." + } + ] + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Base workbook model the document is built on — a SHARED model, or a SHARED_EXTENSION with `allowAsWorkbookBase = true`." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 254, + "description": "Document name." + }, + "queryPresentations": { + "$ref": "#/components/schemas/QueryPresentationsPatchExternal" + }, + "settings": { + "$ref": "#/components/schemas/SettingsPatchExternal" + }, + "summary": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Optional. Caller-supplied note describing the create, written to the history audit trail. When omitted, the server auto-fills it with \"Created document\"." + } + }, + "required": [ + "modelId", + "name" + ], + "additionalProperties": false + }, + "ContainersOnCreate": { + "type": [ + "array", + "null" + ], + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "$ref": "#/components/schemas/PageContainer" + }, + { + "$ref": "#/components/schemas/StackContainer" + } + ] + }, + "description": "Container layout array, or `null` to create a workbook-only document with no dashboard. When `null`, `controls` and `settings` must be omitted." + }, + "GridContainer": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Optional description for the container, providing additional context or information" + }, + "instanceKey": { + "type": "string", + "description": "Unique identifier for this container. Used to reference the container when adding, moving, or removing children." + }, + "name": { + "type": "string", + "description": "Human-readable name for the container, used for easier reference in logic and design" + }, + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + }, + "after": { + "anyOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "before": { + "anyOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/ReferenceContainer" + }, + { + "type": "object", + "properties": { + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number" + }, + "w": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + } + }, + "required": [ + "gridPosition" + ] + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "type": "object", + "properties": { + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number" + }, + "w": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + } + }, + "required": [ + "gridPosition" + ] + } + ] + }, + { + "allOf": [ + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "type": "object", + "properties": { + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number" + }, + "w": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + } + }, + "required": [ + "gridPosition" + ] + } + ] + }, + { + "allOf": [ + { + "anyOf": [ + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "as": { + "type": "string", + "enum": [ + "chart", + "result", + "ai", + "metadata" + ], + "description": "Render mode: \"chart\" for visualization, \"result\" for data table, \"ai\" for AI summary, \"metadata\" for query metadata" + }, + "detachedContent": { + "type": "string", + "description": "Set when a metadata field is detached: local text rendered instead of the query value" + }, + "format": { + "type": "string", + "enum": [ + "subtitle", + "description", + "name" + ], + "description": "Display format when as is \"ai\" or \"metadata\": \"name\" (metadata only), \"subtitle\", or \"description\"" + }, + "id": { + "type": "string", + "pattern": "^[1-9][0-9]*$", + "description": "The query presentation ID this content item references" + }, + "name": { + "type": "string", + "description": "Display name for this query item" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "appearance": { + "oneOf": [ + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "inline" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "tooltip" + ] + } + }, + "required": [ + "as" + ] + } + ], + "description": "Display mode: \"inline\" renders directly, \"tooltip\" shows on hover" + }, + "content": { + "type": "string", + "description": "The text content to display (supports markdown)" + }, + "name": { + "type": "string", + "description": "Display name for this text item (e.g., title, subtitle)" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "textAlign": { + "type": "string", + "enum": [ + "start", + "center", + "end" + ], + "description": "Text alignment: \"start\", \"center\", or \"end\"" + }, + "type": { + "type": "string", + "enum": [ + "inline-text" + ] + } + }, + "required": [ + "instanceKey", + "content", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "appearance": { + "oneOf": [ + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "tabs" + ] + }, + "variant": { + "type": "string", + "enum": [ + "underline", + "bordered" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "buttons" + ] + }, + "variant": { + "type": "string", + "enum": [ + "segment", + "toggle", + "pills" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "list" + ] + }, + "description": { + "type": "boolean" + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "dropdown" + ] + }, + "description": { + "type": "boolean" + } + }, + "required": [ + "as" + ] + } + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "disabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "includeControls": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "target": { + "type": "string" + }, + "uri": { + "type": "string" + }, + "value": { + "type": "string", + "description": "Page link target. Must exactly equal an existing page container’s instanceKey — not its name, label, or a slug. A value matching no page redirects to the main dashboard view with a \"Page not found\" message. Ignored when `uri` is set." + } + } + }, + "description": "Omit to auto-derive one tab per page, kept in sync as pages are added, removed, renamed, or reordered. Set to curate, reorder, or add custom-URL tabs; each option’s `value` must then match a page instanceKey." + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "inline-page-switcher" + ] + } + }, + "required": [ + "instanceKey", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the rich text content block" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "text" + ] + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "control" + ] + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "filter" + ] + }, + "appearance": { + "type": "object", + "properties": { + "control": { + "type": "string", + "enum": [ + "buttonToggle", + "dropdown" + ] + }, + "display": { + "type": "string", + "enum": [ + "inline", + "popover" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + } + }, + "value": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "size": { + "type": "number", + "minimum": 0, + "maximum": 2000, + "description": "Fixed size in px along the parent stack axis (default 16). In grids the size comes from gridPosition; ignored when style.fillSpace is true." + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "inline-spacer" + ] + } + }, + "required": [ + "instanceKey", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end" + ], + "description": "Placement of the line within its slot along the cross axis (default center): horizontal → top/center/bottom, vertical → left/center/right" + }, + "color": { + "type": "string", + "enum": [ + "border1", + "border4", + "text1", + "text4" + ], + "description": "Theme color for the line, subtle → bold (default border4)" + }, + "direction": { + "type": "string", + "enum": [ + "horizontal", + "vertical" + ], + "description": "Line orientation (default horizontal)" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "thickness": { + "anyOf": [ + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + } + ], + "description": "Line thickness in px (default 1)" + }, + "type": { + "type": "string", + "enum": [ + "inline-divider" + ] + } + }, + "required": [ + "instanceKey", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "description": { + "type": "string", + "description": "Lightweight supporting text shown beneath the label, e.g. wire-frame instructions." + }, + "label": { + "type": "string", + "description": "Custom heading. Falls back to a type-derived default (e.g. \"Placeholder query\") when unset." + }, + "placeholderType": { + "type": "string", + "enum": [ + "query", + "control", + "filter", + "text" + ], + "description": "The content type this placeholder stands in for. Unset means no type has been picked yet." + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "placeholder" + ] + } + }, + "required": [ + "instanceKey", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "instanceKey", + "type" + ], + "additionalProperties": {} + } + ] + }, + { + "type": "object", + "properties": { + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number" + }, + "w": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + } + }, + "required": [ + "gridPosition" + ] + } + ] + } + ] + } + }, + "containerType": { + "type": "string", + "enum": [ + "grid" + ] + }, + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "integer", + "minimum": 1, + "description": "Height in grid units (default: 36 for charts)" + }, + "w": { + "type": "integer", + "minimum": 1, + "description": "Width in grid columns on a 24-column grid. Common widths: 24 (full), 12 (half), 8 (third), 6 (quarter). x + w must not exceed 24." + }, + "x": { + "type": "integer", + "minimum": 0, + "description": "X position on a 24-column grid (0=left edge, 12=middle). Items side-by-side share the same y with complementary x values." + }, + "y": { + "type": "integer", + "minimum": 0, + "description": "Y position in grid units (0=top, higher values=lower on page)" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + }, + "metadata": { + "type": "object", + "properties": { + "attachedQueryKey": { + "type": "string", + "description": "Set by the auto-add-tile flow when this container was generated for a specific workbook tab. The server removes containers with a matching `attachedQueryKey` when that tab is deleted. The reducer clears this when the user adds unrelated content (a different query, filter, text tile, page switcher, or sub-container)." + }, + "generatedHeading": { + "type": "boolean", + "description": "Marks the auto-injected heading wrapper (title + description row) created for a tile, so it can be labeled generically and treated as managed." + }, + "locked": { + "type": "boolean", + "description": "Locks the container's internal arrangement so its children cannot be dragged, reordered, resized, or have new items dropped in. Cascades to all descendants. Does not lock the container's own position/size." + } + }, + "description": "Optional bookkeeping for this container (e.g. `attachedQueryKey` for auto-placed tiles)" + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + } + ] + }, + "style": { + "type": "string", + "pattern": "^[a-z0-9-]+$" + } + }, + "required": [ + "instanceKey", + "children", + "containerType" + ], + "description": "Grid container — children are positioned on a grid (each carries a gridPosition)." + }, + "StackContainer": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Optional description for the container, providing additional context or information" + }, + "instanceKey": { + "type": "string", + "description": "Unique identifier for this container. Used to reference the container when adding, moving, or removing children." + }, + "name": { + "type": "string", + "description": "Human-readable name for the container, used for easier reference in logic and design" + }, + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + }, + "after": { + "anyOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "align": { + "type": "string", + "enum": [ + "flex-start", + "flex-end", + "center", + "stretch" + ], + "description": "Cross-axis alignment of children (e.g., center, stretch)" + }, + "before": { + "anyOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "as": { + "type": "string", + "enum": [ + "chart", + "result", + "ai", + "metadata" + ], + "description": "Render mode: \"chart\" for visualization, \"result\" for data table, \"ai\" for AI summary, \"metadata\" for query metadata" + }, + "detachedContent": { + "type": "string", + "description": "Set when a metadata field is detached: local text rendered instead of the query value" + }, + "format": { + "type": "string", + "enum": [ + "subtitle", + "description", + "name" + ], + "description": "Display format when as is \"ai\" or \"metadata\": \"name\" (metadata only), \"subtitle\", or \"description\"" + }, + "id": { + "type": "string", + "pattern": "^[1-9][0-9]*$", + "description": "The query presentation ID this content item references" + }, + "name": { + "type": "string", + "description": "Display name for this query item" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "appearance": { + "oneOf": [ + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "inline" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "tooltip" + ] + } + }, + "required": [ + "as" + ] + } + ], + "description": "Display mode: \"inline\" renders directly, \"tooltip\" shows on hover" + }, + "content": { + "type": "string", + "description": "The text content to display (supports markdown)" + }, + "name": { + "type": "string", + "description": "Display name for this text item (e.g., title, subtitle)" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "textAlign": { + "type": "string", + "enum": [ + "start", + "center", + "end" + ], + "description": "Text alignment: \"start\", \"center\", or \"end\"" + }, + "type": { + "type": "string", + "enum": [ + "inline-text" + ] + } + }, + "required": [ + "instanceKey", + "content", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "appearance": { + "oneOf": [ + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "tabs" + ] + }, + "variant": { + "type": "string", + "enum": [ + "underline", + "bordered" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "buttons" + ] + }, + "variant": { + "type": "string", + "enum": [ + "segment", + "toggle", + "pills" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "list" + ] + }, + "description": { + "type": "boolean" + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "dropdown" + ] + }, + "description": { + "type": "boolean" + } + }, + "required": [ + "as" + ] + } + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "disabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "includeControls": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "target": { + "type": "string" + }, + "uri": { + "type": "string" + }, + "value": { + "type": "string", + "description": "Page link target. Must exactly equal an existing page container’s instanceKey — not its name, label, or a slug. A value matching no page redirects to the main dashboard view with a \"Page not found\" message. Ignored when `uri` is set." + } + } + }, + "description": "Omit to auto-derive one tab per page, kept in sync as pages are added, removed, renamed, or reordered. Set to curate, reorder, or add custom-URL tabs; each option’s `value` must then match a page instanceKey." + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "inline-page-switcher" + ] + } + }, + "required": [ + "instanceKey", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the rich text content block" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "text" + ] + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "control" + ] + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "filter" + ] + }, + "appearance": { + "type": "object", + "properties": { + "control": { + "type": "string", + "enum": [ + "buttonToggle", + "dropdown" + ] + }, + "display": { + "type": "string", + "enum": [ + "inline", + "popover" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + } + }, + "value": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "size": { + "type": "number", + "minimum": 0, + "maximum": 2000, + "description": "Fixed size in px along the parent stack axis (default 16). In grids the size comes from gridPosition; ignored when style.fillSpace is true." + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "inline-spacer" + ] + } + }, + "required": [ + "instanceKey", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "align": { + "type": "string", + "enum": [ + "start", + "center", + "end" + ], + "description": "Placement of the line within its slot along the cross axis (default center): horizontal → top/center/bottom, vertical → left/center/right" + }, + "color": { + "type": "string", + "enum": [ + "border1", + "border4", + "text1", + "text4" + ], + "description": "Theme color for the line, subtle → bold (default border4)" + }, + "direction": { + "type": "string", + "enum": [ + "horizontal", + "vertical" + ], + "description": "Line orientation (default horizontal)" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "thickness": { + "anyOf": [ + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + } + ], + "description": "Line thickness in px (default 1)" + }, + "type": { + "type": "string", + "enum": [ + "inline-divider" + ] + } + }, + "required": [ + "instanceKey", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "description": { + "type": "string", + "description": "Lightweight supporting text shown beneath the label, e.g. wire-frame instructions." + }, + "label": { + "type": "string", + "description": "Custom heading. Falls back to a type-derived default (e.g. \"Placeholder query\") when unset." + }, + "placeholderType": { + "type": "string", + "enum": [ + "query", + "control", + "filter", + "text" + ], + "description": "The content type this placeholder stands in for. Unset means no type has been picked yet." + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "placeholder" + ] + } + }, + "required": [ + "instanceKey", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "instanceKey", + "type" + ], + "additionalProperties": {} + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + }, + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "$ref": "#/components/schemas/StackContainer" + } + ] + } + }, + "containerType": { + "type": "string", + "enum": [ + "stack" + ], + "description": "Stack containers lay out children sequentially in a direction (column or row)" + }, + "direction": { + "type": "string", + "enum": [ + "column", + "row" + ], + "description": "Layout direction: \"row\" lays out horizontally, \"column\" stacks vertically (default if not specified)" + }, + "gap": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "number", + "enum": [ + 9 + ] + }, + { + "type": "number", + "enum": [ + 10 + ] + }, + { + "type": "number", + "enum": [ + 11 + ] + }, + { + "type": "number", + "enum": [ + 12 + ] + }, + { + "type": "number", + "enum": [ + 13 + ] + }, + { + "type": "number", + "enum": [ + 14 + ] + }, + { + "type": "number", + "enum": [ + 15 + ] + }, + { + "type": "number", + "enum": [ + 16 + ] + } + ], + "description": "Space between children (CSS size value)" + }, + "justify": { + "type": "string", + "enum": [ + "flex-start", + "flex-end", + "center", + "space-between" + ], + "description": "Main-axis alignment of children (e.g., start, center, end)" + }, + "metadata": { + "type": "object", + "properties": { + "attachedQueryKey": { + "type": "string", + "description": "Set by the auto-add-tile flow when this container was generated for a specific workbook tab. The server removes containers with a matching `attachedQueryKey` when that tab is deleted. The reducer clears this when the user adds unrelated content (a different query, filter, text tile, page switcher, or sub-container)." + }, + "generatedHeading": { + "type": "boolean", + "description": "Marks the auto-injected heading wrapper (title + description row) created for a tile, so it can be labeled generically and treated as managed." + }, + "locked": { + "type": "boolean", + "description": "Locks the container's internal arrangement so its children cannot be dragged, reordered, resized, or have new items dropped in. Cascades to all descendants. Does not lock the container's own position/size." + } + }, + "description": "Optional bookkeeping for this container (e.g. `attachedQueryKey` for auto-placed tiles)" + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + } + ] + }, + "style": { + "type": "string", + "pattern": "^[a-z0-9-]+$" + }, + "wrap": { + "type": "string", + "enum": [ + "nowrap", + "wrap" + ], + "description": "Whether flex items should wrap to new lines (defaults to nowrap if not specified)" + } + }, + "required": [ + "instanceKey", + "children", + "containerType" + ], + "description": "Stack container — an ordered list of nested children (content, grid, stack, or reference)." + }, + "ReferenceContainer": { + "type": "object", + "properties": { + "containerType": { + "type": "string", + "enum": [ + "reference" + ] + }, + "instanceKey": { + "type": "string" + }, + "referenceKey": { + "type": "string" + } + }, + "required": [ + "containerType", + "instanceKey", + "referenceKey" + ], + "description": "Reference container — points at another container in the collection by its instanceKey." + }, + "PageContainer": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Optional description for the container, providing additional context or information" + }, + "instanceKey": { + "type": "string", + "description": "Unique identifier for this container. Used to reference the container when adding, moving, or removing children." + }, + "name": { + "type": "string", + "description": "Human-readable name for the container, used for easier reference in logic and design" + }, + "breakpoint": { + "type": "string", + "enum": [ + "desktop", + "mobile" + ] + }, + "container": { + "anyOf": [ + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "containerType": { + "type": "string", + "enum": [ + "page" + ] + }, + "media": { + "type": "string", + "enum": [ + "screen", + "print" + ] + } + }, + "required": [ + "instanceKey", + "container", + "containerType" + ], + "description": "Page container — a top-level page wrapping a single grid, stack, or reference container, optionally per breakpoint/media." + }, + "ControlsPatchExternal": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ControlPatchExternal" + }, + "description": "Controls keyed by control ID. Shallow-merged by key — omitted keys are untouched; set to `null` to delete." + }, + "order": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Display order for controls. When present, replaces the existing order." + } + } + }, + "ControlPatchExternal": { + "type": [ + "object", + "null" + ], + "properties": { + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "field": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "FIELD", + "TIMEFRAME" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_SELECTION" + ] + } + }, + "required": [ + "id", + "field", + "kind", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "selectionMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_SELECTION" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "id", + "options", + "selectionMap", + "type" + ] + }, + { + "type": "object", + "properties": { + "computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterId": { + "type": "string" + }, + "isDynamicPreviousPeriod": { + "type": "boolean" + }, + "periodsAgo": { + "type": [ + "number", + "null" + ] + }, + "timeUnitName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "periodsAgo", + "timeUnitName" + ] + } + }, + "filterFieldName": { + "type": "string" + }, + "filterId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "PERIOD_OVER_PERIOD" + ] + } + }, + "required": [ + "computations", + "filterFieldName", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_PICKER" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR" + ] + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "filter": { + "$ref": "#/components/schemas/JsonValue" + }, + "id": { + "type": "string" + } + }, + "required": [ + "fieldName", + "filter", + "id" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_FILTER" + ] + } + }, + "required": [ + "id", + "conjunction", + "filters", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "fieldSelection": { + "oneOf": [ + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "full-model" + ] + } + }, + "required": [ + "mode" + ] + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "auto" + ] + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "topics" + ] + }, + { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "topicName": { + "type": "string" + } + }, + "required": [ + "fieldName" + ] + } + }, + "mode": { + "type": "string", + "enum": [ + "specific" + ] + } + }, + "required": [ + "fields", + "mode" + ] + } + ] + }, + "includeViewNameInLabels": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "DYNAMIC_FILTER" + ] + } + }, + "required": [ + "id", + "fieldSelection", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "defaultValue": { + "type": "integer", + "minimum": 1 + }, + "field": { + "type": "string" + }, + "max": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 1 + }, + "type": { + "type": "string", + "enum": [ + "TOP_N" + ] + }, + "value": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "id", + "defaultValue", + "field", + "type", + "value" + ] + } + ], + "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.). Visibility is determined by placement in the filter-bar container." + }, + "map": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean", + "enum": [ + false + ] + } + ] + }, + "description": "Per-tile field overrides keyed by tab ID. Values are a field name (override) or false (exclude tile from control)." + } + }, + "required": [ + "config" + ] + }, + "JsonValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/components/schemas/JsonValue" + }, + { + "type": "null" + } + ] + } + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/JsonValue" + }, + { + "type": "null" + } + ] + } + } + ], + "description": "Arbitrary JSON value (string, number, boolean, null, object, or array)." + }, + "QueryPresentationsPatchExternal": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/QueryPresentationPatchExternal" + }, + "description": "Query presentations keyed by tab ID. Shallow-merged by key — omitted keys are untouched; set to `null` to delete. Capped at 48 entries per patch. When the request carries no `containers` and the document has a dashboard layout, dashboard-eligible tiles added at new keys are auto-placed on the dashboard's first page (non-renderable types such as CSV / dataset / query-view / dbt tabs are stored but not placed), and containers created by auto-placement are removed when their tile is deleted — containers placed via an explicit `containers` write are left in the layout. When `containers` is present it fully defines the layout; on a workbook-only document (no layout yet) tiles are stored without placement." + }, + "order": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[1-9][0-9]*$" + }, + "description": "Tab display order. When present, replaces the existing order." + } + } + }, + "QueryPresentationPatchExternal": { + "type": [ + "object", + "null" + ], + "properties": { + "aiConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "description": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + }, + "subTitle": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + } + }, + "description": "AI-generated metadata config (subtitle/description auto-generation settings)." + }, + "automaticVis": { + "type": [ + "boolean", + "null" + ], + "description": "When true, the system automatically selects the best visualization type." + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "User-provided tab description." + }, + "editingModelObjectName": { + "type": [ + "string", + "null" + ], + "description": "Model object (view/topic) currently being edited via the dataset/query-view editor. Applies only to dataset / query-view tabs — omitted from reads and rejected on patches for other tab types." + }, + "editingModelObjectNameChange": { + "type": [ + "string", + "null" + ], + "description": "Pending rename of the model object being edited. Applies only to dataset / query-view tabs — omitted from reads and rejected on patches for other tab types." + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of filter field names controlling display order on this tab." + }, + "isSql": { + "type": [ + "boolean", + "null" + ], + "description": "Whether this tab is in raw SQL mode." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 144, + "description": "User-provided tab name." + }, + "prefersChart": { + "type": "boolean", + "description": "When true, the chart view is shown by default instead of the data table." + }, + "query": { + "type": [ + "object", + "null" + ], + "properties": { + "aiGenerated": { + "type": "boolean", + "description": "True when AI generated this query’s SQL; the AI SQL is shown in the advanced SQL box." + }, + "branch_id": { + "type": "string", + "description": "Branch model ID when querying against a model branch." + }, + "calculations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "allow_refs_to_unselected_fields": { + "type": "boolean", + "description": "Set by the Kotlin parser when this calc references fields not selected at the top level (AI SQL-gen produces these; UI-authored calcs do not)." + }, + "calc_name": { + "type": "string", + "description": "Internal identifier for the calculation, used as the column alias." + }, + "description": { + "type": "string", + "description": "Description of the calculation." + }, + "format": { + "type": "string", + "description": "Number/date format string (e.g. \"#,##0.00\")." + }, + "label": { + "type": "string", + "description": "Display label shown in the UI." + }, + "original_formula": { + "type": "string", + "description": "The original Excel-style formula before parsing (e.g. \"=SUM(A1:A10)\")." + }, + "outside_pivot": { + "type": "boolean", + "description": "When true, the calculation is evaluated outside the pivot grouping." + }, + "pushdown": { + "type": [ + "boolean", + "null" + ], + "description": "Per-calc override for whether to evaluate before the row limit. `null` defers to the model-level default." + }, + "sql": { + "type": "string", + "description": "Compiled SQL string produced from the formula." + }, + "sql_expression": { + "description": "Parsed SQL expression tree (serialized)." + }, + "swallow_errors": { + "type": "boolean", + "description": "When true, calculation errors are silently swallowed instead of surfaced." + } + }, + "required": [ + "calc_name" + ], + "additionalProperties": {} + }, + "description": "Table calculations attached to this query." + }, + "column_limit": { + "type": "number", + "description": "Max number of pivot columns to return." + }, + "column_totals": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "aggregation" + ] + } + }, + "required": [ + "type" + ] + }, + "description": "Column-level aggregation totals, keyed by field name." + }, + "controls": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "field": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "FIELD", + "TIMEFRAME" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_SELECTION" + ] + } + }, + "required": [ + "id", + "field", + "kind", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "selectionMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_SELECTION" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "id", + "options", + "selectionMap", + "type" + ] + }, + { + "type": "object", + "properties": { + "computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterId": { + "type": "string" + }, + "isDynamicPreviousPeriod": { + "type": "boolean" + }, + "periodsAgo": { + "type": [ + "number", + "null" + ] + }, + "timeUnitName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "periodsAgo", + "timeUnitName" + ] + } + }, + "filterFieldName": { + "type": "string" + }, + "filterId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "PERIOD_OVER_PERIOD" + ] + } + }, + "required": [ + "computations", + "filterFieldName", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_PICKER" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR" + ] + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "filter": { + "$ref": "#/components/schemas/JsonValue" + }, + "id": { + "type": "string" + } + }, + "required": [ + "fieldName", + "filter", + "id" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_FILTER" + ] + } + }, + "required": [ + "id", + "conjunction", + "filters", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "fieldSelection": { + "oneOf": [ + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "full-model" + ] + } + }, + "required": [ + "mode" + ] + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "auto" + ] + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "topics" + ] + }, + { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "topicName": { + "type": "string" + } + }, + "required": [ + "fieldName" + ] + } + }, + "mode": { + "type": "string", + "enum": [ + "specific" + ] + } + }, + "required": [ + "fields", + "mode" + ] + } + ] + }, + "includeViewNameInLabels": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "DYNAMIC_FILTER" + ] + } + }, + "required": [ + "id", + "fieldSelection", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "defaultValue": { + "type": "integer", + "minimum": 1 + }, + "field": { + "type": "string" + }, + "max": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 1 + }, + "type": { + "type": "string", + "enum": [ + "TOP_N" + ] + }, + "value": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "id", + "defaultValue", + "field", + "type", + "value" + ] + } + ] + }, + "description": "Interactive controls (field selectors, PoP controls) attached to this query." + }, + "cube_metadata": { + "type": "object", + "properties": { + "cube_name": { + "type": "string" + }, + "hash_key": { + "type": "string" + }, + "topic_name": { + "type": "string" + } + }, + "required": [ + "cube_name", + "hash_key", + "topic_name" + ], + "additionalProperties": {}, + "description": "Cube-specific metadata (topic name, cube name, hash key) for cube-backed queries." + }, + "custom_summary_types": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Per-field custom summary functions (e.g. SUM, AVG, COUNT)." + }, + "dbtFileName": { + "type": "string", + "description": "dbt file name when this query is backed by a dbt model." + }, + "dbtMode": { + "type": "boolean", + "description": "Whether this query is in dbt mode." + }, + "default_group_by": { + "type": "boolean", + "description": "When true, all dimensions are implicitly included in GROUP BY." + }, + "dimensionIndex": { + "type": "number", + "description": "Index of the primary dimension used for result ordering." + }, + "executableSQL": { + "type": "string", + "description": "Server-compiled SQL string (read-only, set by the backend)." + }, + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Model field names selected for the query (dimensions + measures)." + }, + "fill_fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Fields whose missing date/time values should be filled with nulls to create continuous series." + }, + "filters": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + } + ] + }, + "description": "Query filters keyed by filter ID." + }, + "filtersUsedInSql": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + } + ] + }, + "description": "Filters that were embedded directly in raw SQL (read-only)." + }, + "join_paths_from_topic_name": { + "type": "string", + "description": "Topic name that determines join path precedence for parsed SQL queries." + }, + "join_via_map": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": "Virtual topic join path overrides, keyed by view name to ordered join path." + }, + "limit": { + "type": "number", + "description": "Row limit for the query." + }, + "manualSort": { + "type": "boolean", + "description": "When true, the user has explicitly set a custom sort order." + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "label": { + "type": "string" + }, + "order": { + "type": "number" + } + }, + "additionalProperties": {} + }, + "description": "Per-field display metadata (format, label, order)." + }, + "offset": { + "type": "number", + "description": "Row offset for pagination." + }, + "parsed": { + "type": "boolean", + "description": "Whether this raw SQL query has been parsed into a semantic query." + }, + "periodOverPeriodTransposed": { + "type": "boolean", + "description": "Whether the period-over-period comparison columns are transposed." + }, + "period_over_period_computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date_filter_field_name": { + "type": "string", + "description": "The date dimension field this comparison is anchored to." + }, + "date_filter_id": { + "type": "string", + "description": "ID of the date filter being offset (if backed by a dashboard filter)." + }, + "is_dynamic_previous_period": { + "type": "boolean", + "description": "When true, the previous period is calculated dynamically relative to the current filter range." + }, + "periods_ago": { + "type": [ + "number", + "null" + ], + "description": "How many periods back to compare (e.g. 1 = previous period). Null if not set." + }, + "time_unit_name": { + "type": [ + "string", + "null" + ], + "description": "Time grain for the offset (e.g. \"month\", \"year\"). Null if not set." + } + }, + "required": [ + "date_filter_field_name", + "periods_ago", + "time_unit_name" + ], + "additionalProperties": {} + }, + "description": "Period-over-period comparison configurations." + }, + "pivots": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field names to pivot on (columns become values)." + }, + "rewriteSql": { + "type": "boolean", + "description": "When true, the backend should rewrite/optimize the SQL." + }, + "row_totals": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "aggregation" + ] + } + }, + "required": [ + "type" + ] + }, + "description": "Row-level aggregation totals, keyed by field name." + }, + "sorts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "column_name": { + "type": "string", + "description": "The model field name to sort by." + }, + "is_column_sort": { + "type": "boolean", + "description": "When true, this sort targets a pivoted column rather than a row dimension." + }, + "pivot_value_map": { + "type": "object", + "additionalProperties": { + "type": [ + "string", + "null" + ] + }, + "description": "Maps pivot field names to specific pivot values, scoping the sort to a single pivot column." + }, + "sort_descending": { + "type": "boolean", + "description": "When true, sort order is descending." + }, + "subtotal_sort": { + "type": "string", + "description": "Field name whose subtotal row should be used as the sort key." + } + }, + "required": [ + "column_name", + "sort_descending" + ], + "additionalProperties": {} + }, + "description": "Sort clauses applied to the query result set." + }, + "sqlSortsEnabled": { + "type": "boolean", + "description": "Whether user-created sorts are enabled on a raw SQL query." + }, + "staticQueryReferences": { + "type": "object", + "additionalProperties": {}, + "description": "Pre-computed query references for AI chat context. Inner shape is `OmniQuery & { model_id: string }`; left as `unknown` to avoid a recursive zod schema. Validated structurally by consumers when they execute the referenced sub-queries." + }, + "table": { + "type": "string", + "description": "Base view (table) name in the model." + }, + "transposed_measures": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Measure field names that have been transposed into rows." + }, + "userEditedSQL": { + "type": "string", + "description": "User-authored raw SQL (empty string when not in SQL mode)." + }, + "version": { + "type": "number", + "description": "Schema version for migration support." + } + }, + "required": [ + "calculations", + "column_totals", + "fields", + "fill_fields", + "filters", + "pivots", + "row_totals", + "sorts", + "table", + "userEditedSQL" + ], + "additionalProperties": {}, + "description": "The semantic query for this tab, minus the server-owned workbook model anchors (modelId / model_extension_id). Omitted on a no-op replay; the server anchors new/changed tiles to the draft." + }, + "resultConfig": { + "type": "object", + "additionalProperties": {}, + "description": "Result display configuration (column widths, frozen columns, conditional formatting, number formatting, etc.)." + }, + "subTitle": { + "type": [ + "string", + "null" + ], + "maxLength": 250, + "description": "User-provided tab subtitle." + }, + "topicName": { + "type": [ + "string", + "null" + ], + "description": "The topic (explore) this query is built on." + }, + "type": { + "type": "string", + "enum": [ + "blank", + "csv", + "query", + "dataset", + "spreadsheet", + "sql", + "dbt", + "query-view", + "linked" + ], + "description": "The query presentation type (e.g. SEMANTIC, SQL, LINKED, SPREADSHEET)." + }, + "visConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "chartType": { + "type": [ + "string", + "null" + ], + "enum": [ + "auto", + "area", + "areaStacked", + "areaStackedPercentage", + "bar", + "barLine", + "barGrouped", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "regionMap", + "markdown", + "omni-ai-summary-markdown", + "pie", + "funnel", + "sankey", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "singleRecord", + "omni-spreadsheet", + "summaryValue", + "svgMap", + "table", + "treemap", + null + ], + "description": "High-level chart type (e.g. \"bar\", \"line\", \"area\")." + }, + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field names used in the visualization axes/series." + }, + "version": { + "type": "number", + "description": "Schema version for vis config migration." + }, + "visConfig": { + "type": "object", + "properties": { + "config": { + "type": "object", + "properties": {}, + "additionalProperties": {}, + "description": "The vis-type-specific spec — KPI rows, chart mark/series, etc. GET nests the spec here; PATCH also accepts it spread flat next to visType for backward compatibility." + }, + "visType": { + "type": [ + "string", + "null" + ], + "enum": [ + "vegalite", + "omni-ai-summary-markdown", + "basic", + "omni-kpi", + "map", + "omni-markdown", + "funnel", + "sankey", + "single-record", + "svg-map", + "treemap", + "omni-spreadsheet", + "spreadsheet-tab", + "summary-value", + "omni-table", + null + ], + "description": "The visualization type (e.g. \"basic\", \"omni-table\")." + } + }, + "additionalProperties": {}, + "description": "Inner visualization config — structure varies by visType." + } + }, + "additionalProperties": {}, + "description": "Visualization configuration for the tile." + }, + "sourceQueryPresentationKey": { + "type": [ + "string", + "null" + ], + "pattern": "^[1-9][0-9]*$", + "description": "For LINKED-type tabs, the record key — the same identifier used as a `queryPresentations.data` key — of the source tile whose query this tab reuses. Null for all other tab types. This is a tile record key, NOT a positional index into `order`." + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + "SettingsPatchExternal": { + "type": "object", + "properties": { + "crossfilterEnabled": { + "type": "boolean", + "description": "When true, clicking a value in one tile filters all other tiles on the dashboard." + }, + "customText": { + "type": [ + "object", + "null" + ], + "properties": { + "queryError": { + "type": "string", + "description": "Custom text shown when a query errors, replacing the default error text." + }, + "queryNoResults": { + "type": "string", + "description": "Custom text shown when a query returns no results, replacing the default empty state." + } + }, + "description": "Custom text replacing default UI strings on the dashboard, e.g. when queries error or return no results." + }, + "facetFilters": { + "type": "boolean", + "description": "When true, dashboard filters are applied per-facet when faceting is active." + }, + "refreshInterval": { + "type": [ + "number", + "null" + ], + "description": "Auto-refresh interval in seconds. Null disables auto-refresh." + }, + "runQueriesOn": { + "type": [ + "string", + "null" + ], + "enum": [ + "current-page", + "all-pages", + null + ], + "description": "Controls whether dashboard queries execute on the visible page or across all pages." + } + }, + "description": "Document settings. Shallow-merged with the existing settings." + }, + "DocumentsV2ReadResponse": { + "type": "object", + "properties": { + "containers": { + "$ref": "#/components/schemas/Containers" + }, + "controls": { + "$ref": "#/components/schemas/ControlsReadExternal" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Base model the document is built on (the `modelId` supplied at create). Immutable — echoed here so a GET round-trips through PATCH; supplying a different value on PATCH is rejected." + }, + "name": { + "type": "string", + "maxLength": 254, + "description": "Document name." + }, + "queryPresentations": { + "$ref": "#/components/schemas/QueryPresentationsReadExternal" + }, + "settings": { + "$ref": "#/components/schemas/SettingsReadExternal" + } + }, + "required": [ + "description", + "modelId", + "name", + "queryPresentations" + ] + }, + "Containers": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "$ref": "#/components/schemas/PageContainer" + }, + { + "$ref": "#/components/schemas/StackContainer" + } + ] + }, + "description": "Container layout array (grid / stack / page / reference containers, recursively nested). The server validates the full structure on apply." + }, + "ControlsReadExternal": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ControlReadExternal" + }, + "description": "Controls keyed by control ID." + }, + "order": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Display order for controls." + } + }, + "required": [ + "data", + "order" + ] + }, + "ControlReadExternal": { + "type": "object", + "properties": { + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "field": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "FIELD", + "TIMEFRAME" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_SELECTION" + ] + } + }, + "required": [ + "id", + "field", + "kind", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "selectionMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_SELECTION" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "id", + "options", + "selectionMap", + "type" + ] + }, + { + "type": "object", + "properties": { + "computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterId": { + "type": "string" + }, + "isDynamicPreviousPeriod": { + "type": "boolean" + }, + "periodsAgo": { + "type": [ + "number", + "null" + ] + }, + "timeUnitName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "periodsAgo", + "timeUnitName" + ] + } + }, + "filterFieldName": { + "type": "string" + }, + "filterId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "PERIOD_OVER_PERIOD" + ] + } + }, + "required": [ + "computations", + "filterFieldName", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_PICKER" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR" + ] + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "filter": { + "$ref": "#/components/schemas/JsonValue" + }, + "id": { + "type": "string" + } + }, + "required": [ + "fieldName", + "filter", + "id" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_FILTER" + ] + } + }, + "required": [ + "id", + "conjunction", + "filters", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "fieldSelection": { + "oneOf": [ + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "full-model" + ] + } + }, + "required": [ + "mode" + ] + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "auto" + ] + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "topics" + ] + }, + { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "topicName": { + "type": "string" + } + }, + "required": [ + "fieldName" + ] + } + }, + "mode": { + "type": "string", + "enum": [ + "specific" + ] + } + }, + "required": [ + "fields", + "mode" + ] + } + ] + }, + "includeViewNameInLabels": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "DYNAMIC_FILTER" + ] + } + }, + "required": [ + "id", + "fieldSelection", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "defaultValue": { + "type": "integer", + "minimum": 1 + }, + "field": { + "type": "string" + }, + "max": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 1 + }, + "type": { + "type": "string", + "enum": [ + "TOP_N" + ] + }, + "value": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "id", + "defaultValue", + "field", + "type", + "value" + ] + } + ], + "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.). Visibility is determined by placement in the filter-bar container." + }, + "map": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean", + "enum": [ + false + ] + } + ] + }, + "description": "Per-tile field overrides keyed by tab ID. Values are a field name (override) or false (exclude tile from control)." + } + }, + "required": [ + "config" + ] + }, + "QueryPresentationsReadExternal": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/QueryPresentationReadExternal" + }, + "description": "Query presentations keyed by tab ID." + }, + "order": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[1-9][0-9]*$" + }, + "description": "Tab display order." + } + }, + "required": [ + "data", + "order" + ] + }, + "QueryPresentationReadExternal": { + "type": "object", + "properties": { + "aiConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "description": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + }, + "subTitle": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + } + }, + "description": "AI-generated metadata config (subtitle/description auto-generation settings)." + }, + "automaticVis": { + "type": [ + "boolean", + "null" + ], + "description": "When true, the system automatically selects the best visualization type." + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "User-provided tab description." + }, + "editingModelObjectName": { + "type": [ + "string", + "null" + ], + "description": "Model object (view/topic) currently being edited via the dataset/query-view editor. Applies only to dataset / query-view tabs — omitted from reads and rejected on patches for other tab types." + }, + "editingModelObjectNameChange": { + "type": [ + "string", + "null" + ], + "description": "Pending rename of the model object being edited. Applies only to dataset / query-view tabs — omitted from reads and rejected on patches for other tab types." + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of filter field names controlling display order on this tab." + }, + "isSql": { + "type": [ + "boolean", + "null" + ], + "description": "Whether this tab is in raw SQL mode." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 144, + "description": "User-provided tab name." + }, + "prefersChart": { + "type": "boolean", + "description": "When true, the chart view is shown by default instead of the data table." + }, + "query": { + "type": [ + "object", + "null" + ], + "properties": { + "aiGenerated": { + "type": "boolean", + "description": "True when AI generated this query’s SQL; the AI SQL is shown in the advanced SQL box." + }, + "branch_id": { + "type": "string", + "description": "Branch model ID when querying against a model branch." + }, + "calculations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "allow_refs_to_unselected_fields": { + "type": "boolean", + "description": "Set by the Kotlin parser when this calc references fields not selected at the top level (AI SQL-gen produces these; UI-authored calcs do not)." + }, + "calc_name": { + "type": "string", + "description": "Internal identifier for the calculation, used as the column alias." + }, + "description": { + "type": "string", + "description": "Description of the calculation." + }, + "format": { + "type": "string", + "description": "Number/date format string (e.g. \"#,##0.00\")." + }, + "label": { + "type": "string", + "description": "Display label shown in the UI." + }, + "original_formula": { + "type": "string", + "description": "The original Excel-style formula before parsing (e.g. \"=SUM(A1:A10)\")." + }, + "outside_pivot": { + "type": "boolean", + "description": "When true, the calculation is evaluated outside the pivot grouping." + }, + "pushdown": { + "type": [ + "boolean", + "null" + ], + "description": "Per-calc override for whether to evaluate before the row limit. `null` defers to the model-level default." + }, + "sql": { + "type": "string", + "description": "Compiled SQL string produced from the formula." + }, + "sql_expression": { + "description": "Parsed SQL expression tree (serialized)." + }, + "swallow_errors": { + "type": "boolean", + "description": "When true, calculation errors are silently swallowed instead of surfaced." + } + }, + "required": [ + "calc_name" + ], + "additionalProperties": {} + }, + "description": "Table calculations attached to this query." + }, + "column_limit": { + "type": "number", + "description": "Max number of pivot columns to return." + }, + "column_totals": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "aggregation" + ] + } + }, + "required": [ + "type" + ] + }, + "description": "Column-level aggregation totals, keyed by field name." + }, + "controls": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "field": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "FIELD", + "TIMEFRAME" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_SELECTION" + ] + } + }, + "required": [ + "id", + "field", + "kind", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "selectionMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_SELECTION" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "id", + "options", + "selectionMap", + "type" + ] + }, + { + "type": "object", + "properties": { + "computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterId": { + "type": "string" + }, + "isDynamicPreviousPeriod": { + "type": "boolean" + }, + "periodsAgo": { + "type": [ + "number", + "null" + ] + }, + "timeUnitName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "periodsAgo", + "timeUnitName" + ] + } + }, + "filterFieldName": { + "type": "string" + }, + "filterId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "PERIOD_OVER_PERIOD" + ] + } + }, + "required": [ + "computations", + "filterFieldName", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_PICKER" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR" + ] + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "filter": { + "$ref": "#/components/schemas/JsonValue" + }, + "id": { + "type": "string" + } + }, + "required": [ + "fieldName", + "filter", + "id" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_FILTER" + ] + } + }, + "required": [ + "id", + "conjunction", + "filters", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "fieldSelection": { + "oneOf": [ + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "full-model" + ] + } + }, + "required": [ + "mode" + ] + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "auto" + ] + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "topics" + ] + }, + { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "topicName": { + "type": "string" + } + }, + "required": [ + "fieldName" + ] + } + }, + "mode": { + "type": "string", + "enum": [ + "specific" + ] + } + }, + "required": [ + "fields", + "mode" + ] + } + ] + }, + "includeViewNameInLabels": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "DYNAMIC_FILTER" + ] + } + }, + "required": [ + "id", + "fieldSelection", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "defaultValue": { + "type": "integer", + "minimum": 1 + }, + "field": { + "type": "string" + }, + "max": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 1 + }, + "type": { + "type": "string", + "enum": [ + "TOP_N" + ] + }, + "value": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "id", + "defaultValue", + "field", + "type", + "value" + ] + } + ] + }, + "description": "Interactive controls (field selectors, PoP controls) attached to this query." + }, + "cube_metadata": { + "type": "object", + "properties": { + "cube_name": { + "type": "string" + }, + "hash_key": { + "type": "string" + }, + "topic_name": { + "type": "string" + } + }, + "required": [ + "cube_name", + "hash_key", + "topic_name" + ], + "additionalProperties": {}, + "description": "Cube-specific metadata (topic name, cube name, hash key) for cube-backed queries." + }, + "custom_summary_types": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Per-field custom summary functions (e.g. SUM, AVG, COUNT)." + }, + "dbtFileName": { + "type": "string", + "description": "dbt file name when this query is backed by a dbt model." + }, + "dbtMode": { + "type": "boolean", + "description": "Whether this query is in dbt mode." + }, + "default_group_by": { + "type": "boolean", + "description": "When true, all dimensions are implicitly included in GROUP BY." + }, + "dimensionIndex": { + "type": "number", + "description": "Index of the primary dimension used for result ordering." + }, + "executableSQL": { + "type": "string", + "description": "Server-compiled SQL string (read-only, set by the backend)." + }, + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Model field names selected for the query (dimensions + measures)." + }, + "fill_fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Fields whose missing date/time values should be filled with nulls to create continuous series." + }, + "filters": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + } + ] + }, + "description": "Query filters keyed by filter ID." + }, + "filtersUsedInSql": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + } + ] + }, + "description": "Filters that were embedded directly in raw SQL (read-only)." + }, + "join_paths_from_topic_name": { + "type": "string", + "description": "Topic name that determines join path precedence for parsed SQL queries." + }, + "join_via_map": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": "Virtual topic join path overrides, keyed by view name to ordered join path." + }, + "limit": { + "type": "number", + "description": "Row limit for the query." + }, + "manualSort": { + "type": "boolean", + "description": "When true, the user has explicitly set a custom sort order." + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "label": { + "type": "string" + }, + "order": { + "type": "number" + } + }, + "additionalProperties": {} + }, + "description": "Per-field display metadata (format, label, order)." + }, + "offset": { + "type": "number", + "description": "Row offset for pagination." + }, + "parsed": { + "type": "boolean", + "description": "Whether this raw SQL query has been parsed into a semantic query." + }, + "periodOverPeriodTransposed": { + "type": "boolean", + "description": "Whether the period-over-period comparison columns are transposed." + }, + "period_over_period_computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date_filter_field_name": { + "type": "string", + "description": "The date dimension field this comparison is anchored to." + }, + "date_filter_id": { + "type": "string", + "description": "ID of the date filter being offset (if backed by a dashboard filter)." + }, + "is_dynamic_previous_period": { + "type": "boolean", + "description": "When true, the previous period is calculated dynamically relative to the current filter range." + }, + "periods_ago": { + "type": [ + "number", + "null" + ], + "description": "How many periods back to compare (e.g. 1 = previous period). Null if not set." + }, + "time_unit_name": { + "type": [ + "string", + "null" + ], + "description": "Time grain for the offset (e.g. \"month\", \"year\"). Null if not set." + } + }, + "required": [ + "date_filter_field_name", + "periods_ago", + "time_unit_name" + ], + "additionalProperties": {} + }, + "description": "Period-over-period comparison configurations." + }, + "pivots": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field names to pivot on (columns become values)." + }, + "rewriteSql": { + "type": "boolean", + "description": "When true, the backend should rewrite/optimize the SQL." + }, + "row_totals": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "aggregation" + ] + } + }, + "required": [ + "type" + ] + }, + "description": "Row-level aggregation totals, keyed by field name." + }, + "sorts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "column_name": { + "type": "string", + "description": "The model field name to sort by." + }, + "is_column_sort": { + "type": "boolean", + "description": "When true, this sort targets a pivoted column rather than a row dimension." + }, + "pivot_value_map": { + "type": "object", + "additionalProperties": { + "type": [ + "string", + "null" + ] + }, + "description": "Maps pivot field names to specific pivot values, scoping the sort to a single pivot column." + }, + "sort_descending": { + "type": "boolean", + "description": "When true, sort order is descending." + }, + "subtotal_sort": { + "type": "string", + "description": "Field name whose subtotal row should be used as the sort key." + } + }, + "required": [ + "column_name", + "sort_descending" + ], + "additionalProperties": {} + }, + "description": "Sort clauses applied to the query result set." + }, + "sqlSortsEnabled": { + "type": "boolean", + "description": "Whether user-created sorts are enabled on a raw SQL query." + }, + "staticQueryReferences": { + "type": "object", + "additionalProperties": {}, + "description": "Pre-computed query references for AI chat context. Inner shape is `OmniQuery & { model_id: string }`; left as `unknown` to avoid a recursive zod schema. Validated structurally by consumers when they execute the referenced sub-queries." + }, + "table": { + "type": "string", + "description": "Base view (table) name in the model." + }, + "transposed_measures": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Measure field names that have been transposed into rows." + }, + "userEditedSQL": { + "type": "string", + "description": "User-authored raw SQL (empty string when not in SQL mode)." + }, + "version": { + "type": "number", + "description": "Schema version for migration support." + } + }, + "required": [ + "calculations", + "column_totals", + "fields", + "fill_fields", + "filters", + "pivots", + "row_totals", + "sorts", + "table", + "userEditedSQL" + ], + "additionalProperties": {}, + "description": "The semantic query for this tab, minus the server-owned workbook model anchors (modelId / model_extension_id). For LINKED-type tabs this field is read-only." + }, + "resultConfig": { + "type": "object", + "additionalProperties": {}, + "description": "Result display configuration (column widths, frozen columns, conditional formatting, number formatting, etc.)." + }, + "subTitle": { + "type": [ + "string", + "null" + ], + "maxLength": 250, + "description": "User-provided tab subtitle." + }, + "topicName": { + "type": [ + "string", + "null" + ], + "description": "The topic (explore) this query is built on." + }, + "type": { + "type": "string", + "enum": [ + "blank", + "csv", + "query", + "dataset", + "spreadsheet", + "sql", + "dbt", + "query-view", + "linked" + ], + "description": "The query presentation type (e.g. SEMANTIC, SQL, LINKED, SPREADSHEET)." + }, + "visConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "chartType": { + "type": [ + "string", + "null" + ], + "enum": [ + "auto", + "area", + "areaStacked", + "areaStackedPercentage", + "bar", + "barLine", + "barGrouped", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "regionMap", + "markdown", + "omni-ai-summary-markdown", + "pie", + "funnel", + "sankey", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "singleRecord", + "omni-spreadsheet", + "summaryValue", + "svgMap", + "table", + "treemap", + null + ], + "description": "High-level chart type (e.g. \"bar\", \"line\", \"area\")." + }, + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field names used in the visualization axes/series." + }, + "version": { + "type": "number", + "description": "Schema version for vis config migration." + }, + "visConfig": { + "type": "object", + "properties": { + "config": { + "type": "object", + "properties": {}, + "additionalProperties": {}, + "description": "The vis-type-specific spec — KPI rows, chart mark/series, etc. GET nests the spec here; PATCH also accepts it spread flat next to visType for backward compatibility." + }, + "visType": { + "type": [ + "string", + "null" + ], + "enum": [ + "vegalite", + "omni-ai-summary-markdown", + "basic", + "omni-kpi", + "map", + "omni-markdown", + "funnel", + "sankey", + "single-record", + "svg-map", + "treemap", + "omni-spreadsheet", + "spreadsheet-tab", + "summary-value", + "omni-table", + null + ], + "description": "The visualization type (e.g. \"basic\", \"omni-table\")." + } + }, + "additionalProperties": {}, + "description": "Inner visualization config — structure varies by visType." + } + }, + "additionalProperties": {}, + "description": "Visualization configuration for the tile." + }, + "sourceQueryPresentationKey": { + "type": [ + "string", + "null" + ], + "pattern": "^[1-9][0-9]*$", + "description": "For LINKED-type tabs, the record key — the same identifier used as a `queryPresentations.data` key — of the source tile whose query this tab reuses. Null for all other tab types. This is a tile record key, NOT a positional index into `order`." + } + }, + "required": [ + "aiConfig", + "automaticVis", + "description", + "filterOrder", + "isSql", + "name", + "prefersChart", + "query", + "resultConfig", + "subTitle", + "topicName", + "type", + "visConfig", + "sourceQueryPresentationKey" + ] + }, + "SettingsReadExternal": { + "type": "object", + "properties": { + "crossfilterEnabled": { + "type": "boolean", + "description": "When true, clicking a value in one tile filters all other tiles on the dashboard." + }, + "customText": { + "type": [ + "object", + "null" + ], + "properties": { + "queryError": { + "type": "string", + "description": "Custom text shown when a query errors, replacing the default error text." + }, + "queryNoResults": { + "type": "string", + "description": "Custom text shown when a query returns no results, replacing the default empty state." + } + }, + "description": "Custom text replacing default UI strings on the dashboard, e.g. when queries error or return no results." + }, + "facetFilters": { + "type": "boolean", + "description": "When true, dashboard filters are applied per-facet when faceting is active." + }, + "refreshInterval": { + "type": [ + "number", + "null" + ], + "description": "Auto-refresh interval in seconds. Null disables auto-refresh." + }, + "runQueriesOn": { + "type": [ + "string", + "null" + ], + "enum": [ + "current-page", + "all-pages", + null + ], + "description": "Controls whether dashboard queries execute on the visible page or across all pages." + } + }, + "required": [ + "crossfilterEnabled", + "customText", + "facetFilters", + "refreshInterval", + "runQueriesOn" + ] + }, + "DocumentsV2PatchDraftResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "draftIdentifier": { + "type": "string", + "description": "Identifier of the draft the patch was applied to." + }, + "identifier": { + "type": "string", + "description": "Published document identifier the draft targets." + }, + "name": { + "type": "string", + "description": "Document name." + } + }, + "required": [ + "description", + "draftIdentifier", + "identifier", + "name" + ] + }, + "DocumentsV2CreateDraftBody": { + "allOf": [ + { + "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" + }, + { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Branch the draft is created on. Omit for a draft on the main (unpublished) workspace." + } + }, + "additionalProperties": false + } + ] + }, + "DocumentsV2PatchDraftBody": { + "type": "object", + "properties": { + "containers": { + "allOf": [ + { + "$ref": "#/components/schemas/Containers" + }, + { + "description": "Container layout. When present, fully replaces the existing layout and disables automatic tile placement for the request." + } + ] + }, + "controls": { + "$ref": "#/components/schemas/ControlsPatchExternal" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 254, + "description": "Document name." + }, + "queryPresentations": { + "$ref": "#/components/schemas/QueryPresentationsPatchExternal" + }, + "settings": { + "$ref": "#/components/schemas/SettingsPatchExternal" + }, + "summary": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Optional. Caller-supplied description of what this patch changes, written to the history audit trail. When omitted, the server auto-generates one from the touched sections." + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The document's base model. Immutable and accepted only so a GET response round-trips through PATCH: a value matching the current model is a no-op, and a differing value is rejected — it cannot re-base the document. Omit it to leave the model untouched." + } + }, + "additionalProperties": false + }, + "DocumentsV2PublishDraftResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "identifier": { + "type": "string", + "description": "Published document identifier." + }, + "name": { + "type": "string", + "description": "Document name." + } + }, + "required": [ + "description", + "identifier", + "name" + ] + }, + "DocumentsV2UpdateIdentifierResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "identifier": { + "type": "string", + "description": "The document identifier after the rename." + }, + "name": { + "type": "string", + "description": "Document name." + } + }, + "required": [ + "description", + "identifier", + "name" + ] + }, + "DocumentsV2UpdateIdentifierBody": { + "type": "object", + "properties": { + "identifier": { + "allOf": [ + { + "$ref": "#/components/schemas/DocumentIdentifier" + }, + { + "description": "New identifier for the document. Must be unique within the organization.", + "example": "new-slug" + } + ] + } + }, + "required": [ + "identifier" + ], + "additionalProperties": false + }, + "EmbedSsoGenerateSessionResponse": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Session ID to use for embedding Omni content" + } + }, + "required": [ + "sessionId" + ] + }, + "EmbedSsoGenerateSessionBody": { + "type": "object", + "properties": { + "externalId": { + "type": "string", + "description": "External identifier for the user (from your system)", + "example": "user-123" + }, + "groups": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional list of non-entity group names to assign to the user. Entity-group membership is managed by the entity parameter.", + "example": [ + "engineering", + "sales" + ] + }, + "name": { + "type": "string", + "description": "Display name for the user", + "example": "John Doe" + }, + "userAttributes": { + "type": "object", + "additionalProperties": {}, + "description": "Optional user attributes for row-level security" + } + }, + "required": [ + "externalId", + "name" + ] + }, + "EvalPromptSetsListResponse": { + "type": "object", + "properties": { + "prompt_sets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalPromptSetListItem" + }, + "description": "Prompt sets matching the query, sorted alphabetically by name." + } + }, + "required": [ + "prompt_sets" + ] + }, + "EvalPromptSetListItem": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description of the prompt set.", + "example": "Regression suite for the orders topic" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the prompt set has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this prompt set is bound to.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "name": { + "type": "string", + "description": "Human-readable name for the prompt set.", + "example": "Orders regression" + }, + "slug": { + "type": "string", + "description": "URL-safe identifier for the prompt set. Unique per `model_id`.", + "example": "orders-regression" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was last updated.", + "example": "2025-01-15T10:00:00.000Z" + }, + "latest_run_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp of the most recent run on this prompt set, if any.", + "example": "2025-01-15T10:05:00.000Z" + }, + "prompt_count": { + "type": "integer", + "description": "Number of prompts in the set.", + "example": 12 + } + }, + "required": [ + "created_at", + "description", + "id", + "is_archived", + "model_id", + "name", + "slug", + "updated_at", + "latest_run_at", + "prompt_count" + ] + }, + "EvalApiError400": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Bad Request: name: Required" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 400 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError401": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Unauthorized: Missing or invalid API key" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 401 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError403": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "AI eval requires at least Querier access on the model" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 403 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError404": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Prompt set not found" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 404 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalPromptSetsCreateResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalPromptSet": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description of the prompt set.", + "example": "Regression suite for the orders topic" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the prompt set has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this prompt set is bound to.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "name": { + "type": "string", + "description": "Human-readable name for the prompt set.", + "example": "Orders regression" + }, + "prompts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalPrompt" + }, + "description": "Prompts that make up the set." + }, + "slug": { + "type": "string", + "description": "URL-safe identifier for the prompt set. Unique per `model_id`.", + "example": "orders-regression" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was last updated.", + "example": "2025-01-15T10:00:00.000Z" + } + }, + "required": [ + "created_at", + "description", + "id", + "is_archived", + "model_id", + "name", + "prompts", + "slug", + "updated_at" + ] + }, + "EvalPrompt": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "expectation": { + "type": [ + "string", + "null" + ], + "description": "The expectation the analysis judge scores the analysis against, or null when none was set.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the prompt.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "prompt_text": { + "type": "string", + "description": "The natural language prompt text the AI is evaluated on.", + "example": "What are the top 5 products by revenue?" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt was last updated.", + "example": "2025-01-15T10:00:00.000Z" + } + }, + "required": [ + "created_at", + "expectation", + "id", + "prompt_text", + "updated_at" + ] + }, + "EvalApiError422": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "A prompt being updated does not belong to this prompt set" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 422 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalPromptSetsCreateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 1024, + "description": "Optional human-readable description of the prompt set. Max 1024 characters.", + "example": "Regression suite for the orders topic" + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this prompt set is bound to.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Human-readable name for the prompt set. 255 characters or fewer.", + "example": "Orders regression" + }, + "prompts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "expectation": { + "type": [ + "string", + "null" + ], + "maxLength": 16000, + "description": "Optional expectation the analysis judge scores the analysis against. Max 16000 characters.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "prompt_text": { + "type": "string", + "minLength": 1, + "maxLength": 8000, + "description": "The natural language prompt text. Max 8000 characters.", + "example": "What are the top 5 products by revenue?" + } + }, + "required": [ + "prompt_text" + ] + }, + "maxItems": 100, + "default": [], + "description": "Initial prompts for the set. Defaults to an empty list. At most 25 prompts." + }, + "slug": { + "type": "string", + "maxLength": 255, + "pattern": "^[a-z][a-z0-9-]*$", + "description": "URL-safe identifier for the prompt set. Must be unique per `model_id` and match `^[a-z][a-z0-9-]*$`. Max 255 characters.", + "example": "orders-regression" + } + }, + "required": [ + "model_id", + "name", + "slug" + ] + }, + "EvalPromptSetsGetResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalPromptSetsUpdateResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalPromptSetsUpdateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 1024, + "description": "New description for the prompt set. Pass `null` to clear. Max 1024 characters." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "New human-readable name for the prompt set. 255 characters or fewer." + }, + "prompts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "expectation": { + "type": [ + "string", + "null" + ], + "maxLength": 16000, + "description": "Optional expectation the analysis judge scores the analysis against. Pass `null` to clear. Max 16000 characters.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Existing prompt id. When provided, updates that prompt; when omitted, a new prompt is created. Prompts not included in this list are removed." + }, + "prompt_text": { + "type": "string", + "minLength": 1, + "maxLength": 8000, + "description": "Updated or new prompt text. Max 8000 characters.", + "example": "What are the top 10 products by revenue this quarter?" + } + }, + "required": [ + "prompt_text" + ] + }, + "maxItems": 100, + "description": "Full desired set of prompts after the update. Prompts omitted from this list are deleted; new prompts (no `id`) are appended in body order. Existing prompts retain their original position — reordering is not supported on this endpoint. At most 25 prompts total." + } + } + }, + "EvalPromptSetsDeleteResponse": { + "type": "object", + "properties": { + "cancelled_job_count": { + "type": "integer", + "description": "Number of in-flight agentic jobs associated with this prompt set that were cancelled as part of the archive.", + "example": 0 + }, + "is_archived": { + "type": "boolean", + "enum": [ + true + ], + "description": "Always `true` on success — archives the prompt set." + } + }, + "required": [ + "cancelled_job_count", + "is_archived" + ] + }, + "EvalApiError500": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Archive committed but a run-cancellation failed; retry to complete" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 500 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalPromptSetsUnarchiveResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalRunsListResponse": { + "type": "object", + "properties": { + "runs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalRunListItem" + }, + "description": "Runs for the prompt set, newest first, filtered to those whose model the caller can access." + } + }, + "required": [ + "runs" + ] + }, + "EvalRunListItem": { + "type": "object", + "properties": { + "branch_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Optional branch ID the run was executed against. Null when run against the main shared model.", + "example": null + }, + "branch_name": { + "type": [ + "string", + "null" + ], + "description": "Display name for the branch, if `branch_id` is set.", + "example": null + }, + "completed_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run reached a terminal state.", + "example": null + }, + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description for the run.", + "example": null + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the run has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this run was executed against.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "prompt_set_id": { + "type": "string", + "format": "uuid", + "description": "The prompt set this run was created from.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "run_number": { + "type": "integer", + "description": "Sequential, per-prompt-set run number.", + "example": 3 + }, + "stats": { + "$ref": "#/components/schemas/EvalRunStats" + }, + "status": { + "type": "string", + "enum": [ + "RUNNING", + "COMPLETE", + "CANCELLED" + ], + "description": "Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly once.", + "example": "RUNNING" + } + }, + "required": [ + "branch_id", + "branch_name", + "completed_at", + "created_at", + "description", + "id", + "is_archived", + "model_id", + "prompt_set_id", + "run_number", + "stats", + "status" + ] + }, + "EvalRunStats": { + "type": "object", + "properties": { + "terminal": { + "type": "integer", + "description": "Number of per-prompt jobs that have reached a terminal state (COMPLETE, FAILED, or CANCELLED).", + "example": 8 + }, + "total": { + "type": "integer", + "description": "Total number of per-prompt jobs in the run.", + "example": 12 + } + }, + "required": [ + "terminal", + "total" + ] + }, + "EvalRunsCreateResponse": { + "type": "object", + "properties": { + "job_count": { + "type": "integer", + "description": "Number of per-prompt agentic jobs created for this run (one per prompt that fanned out successfully). Enqueue onto the work queue happens after creation and is best-effort, so this count reflects jobs created, not necessarily those successfully enqueued.", + "example": 12 + }, + "run": { + "$ref": "#/components/schemas/EvalRunDetail" + } + }, + "required": [ + "job_count", + "run" + ] + }, + "EvalRunDetail": { + "type": "object", + "properties": { + "branch_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Optional branch ID the run was executed against. Null when run against the main shared model.", + "example": null + }, + "branch_name": { + "type": [ + "string", + "null" + ], + "description": "Display name for the branch, if `branch_id` is set.", + "example": null + }, + "completed_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run reached a terminal state.", + "example": null + }, + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description for the run.", + "example": null + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the run has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this run was executed against.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "prompt_set_id": { + "type": "string", + "format": "uuid", + "description": "The prompt set this run was created from.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalRunResult" + }, + "description": "Per-prompt results for this run, ordered by their creation order in the prompt set." + }, + "run_number": { + "type": "integer", + "description": "Sequential, per-prompt-set run number.", + "example": 3 + }, + "status": { + "type": "string", + "enum": [ + "RUNNING", + "COMPLETE", + "CANCELLED" + ], + "description": "Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly once.", + "example": "RUNNING" + } + }, + "required": [ + "branch_id", + "branch_name", + "completed_at", + "created_at", + "description", + "id", + "is_archived", + "model_id", + "prompt_set_id", + "results", + "run_number", + "status" + ], + "description": "The newly created run with its initial results." + }, + "EvalRunResult": { + "type": "object", + "properties": { + "agentic_job": { + "$ref": "#/components/schemas/EvalRunResultAgenticJob" + }, + "ai_timing_ms": { + "type": [ + "integer", + "null" + ], + "description": "Strict main-agent LLM processing time in milliseconds — the measured model-call duration, excluding tool execution and subagent model calls (those count toward `tool_timing_ms`). Shown as \"AI time\" in the UI. Runs recorded before this was measured fall back to an approximation (`timing_ms` minus tool latency).", + "example": 4121 + }, + "cost": { + "type": [ + "number", + "null" + ], + "description": "Total LLM cost (USD) for this prompt, if available.", + "example": 0.0021 + }, + "error_reason": { + "type": [ + "string", + "null" + ], + "description": "Failure reason string for prompts whose underlying job failed.", + "example": null + }, + "expectation": { + "type": [ + "string", + "null" + ], + "description": "The prompt's expectation as of run creation (snapshotted, so later prompt edits don't change past runs), or null when none was set. The analysis judge scores the analysis against it.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the run result row.", + "example": "aa0e8400-e29b-41d4-a716-446655440005" + }, + "prompt": { + "type": "string", + "description": "The prompt text that was evaluated.", + "example": "What are the top 5 products by revenue?" + }, + "query_count": { + "type": [ + "integer", + "null" + ], + "description": "Number of warehouse queries the underlying job ran. Null for runs executed before this metric was recorded.", + "example": 4 + }, + "query_timing_ms": { + "type": [ + "integer", + "null" + ], + "description": "Total wall-clock time (milliseconds) the underlying job spent running warehouse queries — a proxy for query execution time. Null for runs executed before this metric was recorded.", + "example": 1800 + }, + "score": { + "type": [ + "number", + "null" + ], + "description": "Numeric judge score for this prompt result, if scoring ran.", + "example": 0.9 + }, + "scoring_cost": { + "type": [ + "number", + "null" + ], + "description": "Total LLM cost (USD) for scoring this prompt result.", + "example": 0.0004 + }, + "timing_ms": { + "type": [ + "integer", + "null" + ], + "description": "Total `/generate` wall-time in milliseconds — LLM processing plus inner-loop tool execution. `ai_timing_ms` and `tool_timing_ms` split this; warehouse query time is separate (`query_timing_ms`).", + "example": 4321 + }, + "tool_timing_ms": { + "type": [ + "integer", + "null" + ], + "description": "Inner-loop tool latency in milliseconds — time spent running tools the model invoked (model and field-value lookups, query planning), excluding the warehouse query itself (`query_timing_ms`). Null for runs recorded before per-tool latency was tracked.", + "example": 200 + } + }, + "required": [ + "agentic_job", + "ai_timing_ms", + "cost", + "error_reason", + "expectation", + "id", + "prompt", + "query_count", + "query_timing_ms", + "score", + "scoring_cost", + "timing_ms", + "tool_timing_ms" + ] + }, + "EvalRunResultAgenticJob": { + "type": "object", + "properties": { + "conversation_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Conversation the agentic job belongs to.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Agentic job identifier.", + "example": "990e8400-e29b-41d4-a716-446655440004" + }, + "state": { + "type": "string", + "enum": [ + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED" + ], + "description": "Current state of the agentic job that ran this prompt.", + "example": "COMPLETE" + } + }, + "required": [ + "conversation_id", + "id", + "state" + ] + }, + "EvalApiError429": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Too many active runs; wait for an in-flight run to finish" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 429 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError503": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "AI eval is paused for this organization" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 503 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalRunsCreateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 1024, + "description": "Optional human-readable description for the run. Pass `null` to clear (or omit). Max 1024 characters.", + "example": "Re-running after switching to gpt-4o for query generation" + }, + "prompt_set_id": { + "type": "string", + "format": "uuid", + "description": "The prompt set to execute.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "run_config": { + "type": "object", + "properties": { + "branch_id": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID to run against. Must be a branch of the prompt set's model.", + "example": "440e8400-e29b-41d4-a716-446655440006" + } + }, + "description": "Per-run configuration. Optional — omit if no overrides." + } + }, + "required": [ + "prompt_set_id" + ] + }, + "EvalRunsGetResponse": { + "type": "object", + "properties": { + "run": { + "$ref": "#/components/schemas/EvalRunDetail" + } + }, + "required": [ + "run" + ] + }, + "EvalRunsDeleteResponse": { + "type": "object", + "properties": { + "is_archived": { + "type": "boolean", + "enum": [ + true + ], + "description": "Always `true` on success — the run has been archived." + } + }, + "required": [ + "is_archived" + ] + }, + "EvalRunsCancelResponse": { + "type": "object", + "properties": { + "cancelled": { + "type": "integer", + "description": "Number of per-prompt agentic jobs that were cancelled by this request.", + "example": 4 + }, + "run": { + "allOf": [ + { + "$ref": "#/components/schemas/EvalRunDetail" + }, + { + "description": "The cancelled run. `status: CANCELLED` and `is_archived: true` after this call." + } + ] + }, + "total": { + "type": "integer", + "description": "Total number of per-prompt jobs in the run.", + "example": 12 + } + }, + "required": [ + "cancelled", + "run", + "total" + ] + }, + "EvalRunsUnarchiveResponse": { + "type": "object", + "properties": { + "is_archived": { + "type": "boolean", + "enum": [ + false + ], + "description": "Always `false` on success — the run has been unarchived." + } + }, + "required": [ + "is_archived" + ] + }, + "FoldersListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "_count": { + "type": "object", + "properties": { + "documents": { + "type": "number", + "description": "Number of documents in the folder" + }, + "favorites": { + "type": "number", + "description": "Number of users who have favorited this folder" + } + }, + "required": [ + "documents", + "favorites" + ], + "description": "Count statistics for the folder" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique folder identifier" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels associated with the folder" + }, + "name": { + "type": "string", + "description": "Name of the folder", + "example": "My Reports" + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the folder owner" + }, + "path": { + "type": "string", + "description": "Full path to the folder", + "example": "/shared/reports/my-reports" + }, + "url": { + "type": "string", + "description": "URL to view the folder in the Omni UI.", + "example": "https://org.omni.co/f/my-reports" + } + }, + "required": [ + "id", + "name", + "ownerId", + "path", + "url" + ] + }, + "description": "List of folders" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "FoldersCreateResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "ID of the created folder" + }, + "name": { + "type": "string", + "description": "Name of the created folder" + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the folder owner" + }, + "path": { + "type": "string", + "description": "Full path to the folder" + }, + "scope": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Share scope of the folder" + } + }, + "required": [ + "id", + "name", + "ownerId", + "path", + "scope" + ] + }, + "FoldersCreateBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Name of the folder to create", + "example": "My New Folder" + }, + "parentFolderId": { + "type": "string", + "format": "uuid", + "description": "Parent folder ID (omit to create at root level)" + }, + "scope": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Share scope for the folder" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID to create the folder as (for org-scoped API keys only)" + } + }, + "required": [ + "name" + ] + }, + "FoldersDeleteResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the folder was deleted successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersUpdateResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Folder ID" + }, + "name": { + "type": "string", + "description": "Updated folder name" + }, + "path": { + "type": "string", + "description": "Updated URL path segment for the folder (the folder's own segment only)" + } + }, + "required": [ + "id", + "name", + "path" + ] + }, + "FoldersUpdateBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "New display name for the folder", + "example": "Q1 Reports" + }, + "path": { + "type": "string", + "minLength": 1, + "pattern": "^[a-zA-Z0-9-]+$", + "description": "New URL path segment for the folder (alphanumeric and dashes only). This is only the folder's own segment, not the full hierarchical path.", + "example": "q1-reports" + }, + "resolvePathConflict": { + "type": "boolean", + "default": false, + "description": "When true, automatically resolves path collisions with existing folders by appending a numeric suffix (e.g., my-path-1). When false (default), returns 409 Conflict if the path is already taken. Does not apply to reserved paths, which are always rejected with 400." + } + } + }, + "FoldersGetPermissionsResponse": { + "type": "object", + "properties": { + "permits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "description": "Whether access boost is enabled for this permit" + }, + "role": { + "type": "string", + "description": "Content role (e.g., VIEWER, EDITOR, MANAGER)", + "example": "VIEWER" + }, + "userGroupId": { + "type": "string", + "description": "User group ID if this is a group permit" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID if this is a user permit" + } + }, + "required": [ + "role" + ] + }, + "description": "List of permission permits for the folder" + } + }, + "required": [ + "permits" + ] + }, + "FoldersAddPermissionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the permissions were added successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersAddPermissionsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "default": false, + "description": "Whether to grant access boost" + }, + "role": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "Content role to assign (VIEWER, EDITOR, or MANAGER)", + "example": "VIEWER" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to grant permission to" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to grant permission to" + } + }, + "required": [ + "role" + ], + "additionalProperties": false + }, + "FoldersUpdatePermissionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the permissions were updated successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersUpdatePermissionsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "description": "Whether to grant access boost" + }, + "role": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "New content role to assign" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to update permissions for" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to update permissions for" + } + }, + "additionalProperties": false + }, + "FoldersRevokePermissionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the permissions were revoked successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersRevokePermissionsBody": { + "type": "object", + "properties": { + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to revoke permissions from" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to revoke permissions from" + } + }, + "additionalProperties": false + }, + "LabelsListResponse": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "description": "List of labels" + } + }, + "required": [ + "labels" + ] + }, + "LabelsCreateResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsCreateBody": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "default": null, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "default": null, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "default": false, + "description": "Show label on homepage. Requires admin permissions." + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 25, + "description": "Label name", + "example": "important" + }, + "verified": { + "type": "boolean", + "default": false, + "description": "Mark as verified label. Requires admin permissions." + } + }, + "required": [ + "name" + ] + }, + "LabelsGetResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsUpdateResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsUpdateBody": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Show label on homepage. Requires admin permissions to modify." + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 25, + "description": "Label name", + "example": "important" + }, + "verified": { + "type": "boolean", + "description": "Mark as verified label. Requires admin permissions to modify." + } + } + }, + "ModelSuggestionsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelSuggestion" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "ModelSuggestion": { + "type": "object", + "properties": { + "aiModifiedAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of the last AI write (create or AI update). Unaffected by dismiss/restore." + }, + "category": { + "type": "string", + "description": "Suggestion category, e.g. `missing_context`.", + "example": "missing_context" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of when the suggestion was created." + }, + "evidence": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/components/schemas/SuggestionEvidenceItem" + }, + "description": "Source evidence for the suggestion. Null for rows created before evidence was tracked; `[]` when none was cited." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the suggestion." + }, + "ignoreReason": { + "type": [ + "string", + "null" + ], + "description": "Optional free-text reason recorded when the suggestion was dismissed." + }, + "ignoredAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "ISO 8601 timestamp of dismissal, or null if active." + }, + "ignoredBy": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "User id that dismissed the suggestion, or null if active." + }, + "priority": { + "type": "integer", + "minimum": 1, + "maximum": 10, + "description": "Priority from 1 (highest) to 10 (lowest).", + "example": 1 + }, + "proposedChanges": { + "$ref": "#/components/schemas/SuggestionProposedChanges" + }, + "rationale": { + "type": "string", + "description": "Explanation of why the suggestion was made." + }, + "title": { + "type": "string", + "description": "Short human-readable title." + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of the last write of any kind, including dismiss/restore." + } + }, + "required": [ + "aiModifiedAt", + "category", + "createdAt", + "evidence", + "id", + "ignoreReason", + "ignoredAt", + "ignoredBy", + "priority", + "proposedChanges", + "rationale", + "title", + "updatedAt" + ] + }, + "SuggestionEvidenceItem": { + "type": "object", + "properties": { + "capturedAt": { + "type": "string", + "description": "ISO 8601 timestamp of when the evidence was captured." + }, + "chatAiSessionId": { + "type": "string", + "format": "uuid", + "description": "Chat session that motivated the suggestion." + }, + "type": { + "type": "string", + "enum": [ + "ai_chat" + ] + } + }, + "required": [ + "capturedAt", + "chatAiSessionId", + "type" + ] + }, + "SuggestionProposedChanges": { + "type": "object", + "properties": { + "edits": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SuggestionContextEdit" + } + }, + "kind": { + "type": "string", + "enum": [ + "context_edits" + ] + } + }, + "required": [ + "edits", + "kind" + ], + "description": "The change(s) the suggestion would apply to the model." + }, + "SuggestionContextEdit": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "The model field being edited (e.g. `ai_context`).", + "example": "ai_context" + }, + "target": { + "type": "string", + "description": "Dot-path identifying what the edit applies to, e.g. `views.orders.fields.status`.", + "example": "views.orders" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "The proposed value for the field." + } + }, + "required": [ + "field", + "target", + "value" + ] + }, + "ScheduleSuggestionsResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The schedule (trigger) id." + }, + "sharedModelId": { + "type": "string", + "format": "uuid", + "description": "The shared model the schedule generates suggestions for." + }, + "status": { + "type": "string", + "enum": [ + "enabled" + ] + }, + "timezone": { + "type": "string", + "description": "IANA timezone the schedule runs in.", + "example": "America/New_York" + } + }, + "required": [ + "id", + "sharedModelId", + "status", + "timezone" + ] + }, + "ScheduleSuggestionsBody": { + "type": "object", + "properties": { + "timezone": { + "type": "string", + "default": "UTC", + "description": "IANA timezone the schedule fires in (e.g. `America/New_York`). Generation currently runs once daily at ~2 AM in this timezone. Defaults to `UTC`.", + "example": "America/New_York" + } + }, + "additionalProperties": false + }, + "IgnoreSuggestionBody": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "maxLength": 4000, + "description": "Optional free-text reason for dismissing the suggestion.", + "example": "Already covered by an existing field description." + } + }, + "additionalProperties": false + }, + "ModelsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseModelId": { + "type": [ + "string", + "null" + ], + "description": "Base model ID for branch/extension models" + }, + "branches": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Branch ID" + }, + "name": { + "type": "string", + "description": "Branch name" + } + }, + "required": [ + "id", + "name" + ] + }, + "description": "Active branches (if include=activeBranches)" + }, + "connectionId": { + "type": [ + "string", + "null" + ], + "description": "Connection ID" + }, + "createdAt": { + "type": "string", + "description": "Creation timestamp" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Deletion timestamp" + }, + "id": { + "type": "string", + "description": "Model ID" + }, + "modelKind": { + "type": [ + "string", + "null" + ], + "description": "Model kind" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Model name" + }, + "updatedAt": { + "type": "string", + "description": "Last update timestamp" + } + }, + "required": [ + "baseModelId", + "connectionId", + "createdAt", + "deletedAt", + "id", + "modelKind", + "name", + "updatedAt" + ] + }, + "description": "List of model records" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "CreateModelSchemaBase": { + "type": "object", + "properties": { + "accessGrants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "accessBoostable": { + "type": "boolean" + }, + "allowedValues": { + "type": "array", + "items": { + "type": "string" + } + }, + "codeComments": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "ignored": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "userAttribute": { + "type": "string" + } + }, + "required": [ + "accessBoostable", + "name" + ] + }, + "description": "Access grants for the model" + }, + "allowAsWorkbookBase": { + "type": "boolean", + "description": "Allow this model as a workbook base" + }, + "baseModelId": { + "type": "string", + "description": "Base model ID for extension or branch models" + }, + "connectionId": { + "type": "string", + "description": "Connection ID for the model" + }, + "modelKind": { + "anyOf": [ + { + "type": "string", + "enum": [ + "SCHEMA" + ] + }, + { + "type": "string", + "enum": [ + "SHARED" + ] + }, + { + "type": "string", + "enum": [ + "SHARED_EXTENSION" + ] + }, + { + "type": "string", + "enum": [ + "BRANCH" + ] + } + ], + "default": "SCHEMA", + "description": "Kind of model to create" + }, + "modelName": { + "type": "string", + "description": "Name for the model" + }, + "usesIsolatedBranches": { + "type": "boolean", + "description": "For SHARED_EXTENSION models, controls if branches are shown on extension model page instead of parent shared model" + } + }, + "required": [ + "connectionId" + ] + }, + "ModelsUpdateResponse": { + "type": "object", + "properties": { + "model": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Model ID" + }, + "name": { + "type": "string", + "description": "Updated model name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Updated model details" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + } + }, + "required": [ + "model", + "success" + ] + }, + "ModelsUpdateBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "New name for the model", + "example": "My Renamed Model" + } + }, + "required": [ + "name" + ] + }, + "JobsGetStatusResponse": { + "type": "object", + "properties": { + "job_id": { + "type": "string", + "description": "The job ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "job_type": { + "type": "string", + "description": "The type of job (e.g., REFRESH_SCHEMA)", + "example": "REFRESH_SCHEMA" + }, + "status": { + "type": "string", + "enum": [ + "IN_PROGRESS", + "COMPLETED", + "FAILED" + ], + "description": "Current status of the job", + "example": "COMPLETED" + } + }, + "required": [ + "job_id", + "job_type", + "status" + ] + }, + "ModelsGetSchemasResponse": { + "type": "object", + "properties": { + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Sorted list of all available schema names (catalog-scoped if applicable, e.g. warehouse.reporting)" + } + }, + "required": [ + "schemas" + ] + }, + "ModelsGetViewResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "views": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "View description" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Field name" + }, + "type": { + "type": "string", + "enum": [ + "dimension", + "measure", + "filter" + ], + "description": "Field type" + } + }, + "required": [ + "name", + "type" + ] + }, + "description": "Fields in the view" + }, + "hidden": { + "type": "boolean", + "description": "Whether the view is hidden" + }, + "label": { + "type": "string", + "description": "View label" + }, + "name": { + "type": "string", + "description": "View name" + } + }, + "required": [ + "fields", + "name" + ] + }, + "description": "List of views" + } + }, + "required": [ + "success", + "views" + ] + }, + "ModelsUpdateViewBody": { + "type": "object", + "properties": { + "aiContext": { + "type": "string", + "description": "AI context for the view" + }, + "description": { + "type": "string", + "description": "View description" + }, + "format": { + "type": "string", + "description": "View format" + }, + "hidden": { + "type": "boolean", + "description": "Whether the view is hidden" + }, + "label": { + "type": "string", + "description": "View label" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the view" + } + } + }, + "ModelsUpdateFieldBody": { + "type": "object", + "properties": { + "aiContext": { + "type": "string", + "description": "AI context for the field" + }, + "allValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Deprecated: use sampleValues instead" + }, + "binBoundaries": { + "type": "array", + "items": { + "type": "number" + }, + "description": "Bin boundaries for binned fields" + }, + "binLabels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels for bins" + }, + "description": { + "type": "string", + "description": "Field description" + }, + "drillFields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Drill-down fields" + }, + "elseValue": { + "type": "string", + "description": "Else value for grouped fields" + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "description": "Filters for the field" + }, + "format": { + "type": "string", + "description": "Field format" + }, + "groupFilters": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Group filters" + }, + "groupLabel": { + "type": "string", + "description": "Group label" + }, + "groupNames": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Group names" + }, + "hidden": { + "type": "boolean", + "description": "Whether the field is hidden" + }, + "ignored": { + "type": "boolean", + "description": "Whether the field is ignored" + }, + "isCalc": { + "type": "boolean", + "description": "Whether this is a calculation field" + }, + "label": { + "type": "string", + "description": "Field label" + }, + "newFieldName": { + "type": "string", + "description": "New field name (for rename)" + }, + "newViewName": { + "type": "string", + "description": "New view name (for move)" + }, + "sampleValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Sample values for the field" + }, + "sql": { + "type": "string", + "description": "SQL expression for the field" + }, + "synonyms": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Synonyms for the field" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the field" + }, + "topicContext": { + "type": "string", + "description": "Topic context for the field" + } + } + }, + "ModelsListTopicsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "topics": { + "type": "array", + "items": { + "type": "object", + "properties": { + "base_view_name": { + "type": "string", + "description": "Base view name for the topic" + }, + "description": { + "type": "string", + "description": "Topic description" + }, + "group_label": { + "type": "string", + "description": "Group label" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "name": { + "type": "string", + "description": "Topic name" + } + }, + "required": [ + "base_view_name", + "name" + ] + }, + "description": "List of topics" + } + }, + "required": [ + "success", + "topics" + ] + }, + "ModelsGetTopicResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "topic": { + "type": "object", + "properties": { + "base_view_name": { + "type": "string", + "description": "Base view name for the topic" + }, + "description": { + "type": "string", + "description": "Topic description" + }, + "group_label": { + "type": "string", + "description": "Group label" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "name": { + "type": "string", + "description": "Topic name" + }, + "relationships": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Relationships for the topic" + }, + "views": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Views available in the topic" + } + }, + "required": [ + "base_view_name", + "name", + "relationships", + "views" + ], + "description": "Topic details with relationships and views" + } + }, + "required": [ + "success", + "topic" + ] + }, + "ModelsUpdateTopicBody": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Topic description" + }, + "groupLabel": { + "type": "string", + "description": "Group label for the topic" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "newTopicName": { + "type": "string", + "description": "New topic name (for rename)" + } + } + }, + "ModelsCreateFieldBody": { + "type": "object", + "properties": { + "aggregateType": { + "type": "string", + "enum": [ + "AVERAGE", + "COUNT", + "COUNT_DISTINCT", + "LIST", + "MAX", + "MIN", + "SUM", + "MEDIAN", + "PERCENTILE", + "AVERAGE_DISTINCT_ON", + "SUM_DISTINCT_ON", + "MEDIAN_DISTINCT_ON", + "PERCENTILE_DISTINCT_ON", + "SEMANTIC_VIEW_AGG" + ], + "description": "Aggregate type for measures. Setting this property promotes the field to a measure (written under `measures:`); omit it to create a dimension (written under `dimensions:`). Values must be uppercase canonical names.", + "example": "SUM" + }, + "aiContext": { + "type": "string", + "description": "AI context for the field" + }, + "description": { + "type": "string", + "description": "Field description" + }, + "fieldName": { + "type": "string", + "description": "Field name", + "example": "total_revenue" + }, + "format": { + "type": "string", + "description": "Field format" + }, + "hidden": { + "type": "boolean", + "description": "Whether the field is hidden" + }, + "label": { + "type": "string", + "description": "Field label" + }, + "sql": { + "type": "string", + "description": "SQL expression for the field" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the field" + }, + "topicContext": { + "type": "string", + "description": "Topic context for topic-scoped fields" + }, + "viewName": { + "type": "string", + "description": "View to add the field to", + "example": "orders" + } + }, + "required": [ + "fieldName", + "viewName" + ], + "additionalProperties": false + }, + "ModelsRefreshResponse": { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "description": "Job ID for the refresh operation" + }, + "modelId": { + "type": "string", + "description": "Model ID being refreshed" + }, + "status": { + "type": "string", + "enum": [ + "running", + "completed", + "failed" + ], + "description": "Current status of the refresh" + } + }, + "required": [ + "jobId", + "modelId", + "status" + ] + }, + "ModelsValidateResponse": { + "type": "object", + "properties": { + "issues": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "Field name with the issue" + }, + "message": { + "type": "string", + "description": "Validation issue message" + }, + "severity": { + "type": "string", + "enum": [ + "error", + "warning" + ], + "description": "Issue severity" + }, + "view": { + "type": "string", + "description": "View name with the issue" + } + }, + "required": [ + "message", + "severity" + ] + }, + "description": "List of validation issues" + }, + "valid": { + "type": "boolean", + "description": "Whether the model is valid" + } + }, + "required": [ + "issues", + "valid" + ] + }, + "ModelsMigrateBody": { + "type": "object", + "properties": { + "branchName": { + "type": "string", + "description": "Branch name for the target model" + }, + "commitMessage": { + "type": "string", + "description": "Commit message for git sync" + }, + "deleteViewsAndTopicsMissingFromSource": { + "type": "boolean", + "default": true, + "description": "When true (default), views and topics in the target model that are missing from the migrated source are deleted (the source is treated as the complete model). When false, they are kept (inherited) instead — useful when the source git ref may be missing objects that exist in omni but not in git, e.g. a newly synced schema." + }, + "gitRef": { + "type": "string", + "description": "Git reference" + }, + "targetModelId": { + "type": "string", + "format": "uuid", + "description": "Target model ID to migrate to" + } + }, + "required": [ + "targetModelId" + ] + }, + "ModelsDbtExposuresResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtExposureWithMeta" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "DbtExposureWithMeta": { + "type": "object", + "properties": { + "dashboard_identifier": { + "type": "string", + "description": "Identifier of the dashboard that generated this exposure" + }, + "deduplication_name": { + "type": "string", + "description": "A unique name for this exposure. Use this instead of exposure.name to avoid duplicate names, or use it as a fallback when exposure.name collides with another exposure." + }, + "exposure": { + "$ref": "#/components/schemas/DbtExposure" + } + }, + "required": [ + "dashboard_identifier", + "deduplication_name", + "exposure" + ] + }, + "DbtExposure": { + "type": "object", + "properties": { + "depends_on": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of dbt model references (e.g. ref('model_name'))", + "example": [ + "ref('orders')", + "ref('customers')" + ] + }, + "label": { + "type": "string", + "description": "Original dashboard name" + }, + "name": { + "type": "string", + "description": "Sanitized exposure name. May contain duplicates across exposures; use deduplication_name for a guaranteed-unique alternative.", + "example": "my_dashboard" + }, + "owner": { + "$ref": "#/components/schemas/DbtExposureOwner" + }, + "type": { + "type": "string", + "enum": [ + "dashboard", + "notebook", + "analysis", + "ml", + "application" + ], + "description": "Type of the exposure", + "example": "dashboard" + }, + "url": { + "type": "string", + "description": "URL of the dashboard" + } + }, + "required": [ + "depends_on", + "name", + "owner", + "type" + ], + "description": "The dbt exposure for this dashboard." + }, + "DbtExposureOwner": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email of the dashboard owner" + }, + "name": { + "type": "string", + "description": "Name of the dashboard owner" + } + }, + "required": [ + "email", + "name" + ] + }, + "ModelsBranchDbtBody": { + "type": "object", + "properties": { + "dbt_environment_id": { + "type": "string", + "format": "uuid", + "description": "ID of the dbt environment to activate on this branch", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "dbt_git_branch": { + "type": "string", + "description": "Git branch to associate with the dbt environment", + "example": "feature/new-metrics" + } + }, + "required": [ + "dbt_environment_id" + ] + }, + "JobCreatedResponse": { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "description": "ID of the created job. Poll GET /api/v1/jobs/{jobId}/status for its status.", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "jobId" + ] + }, + "ModelsMergeBranchResponse": { + "type": "object", + "properties": { + "failed_drafts_count": { + "type": "number", + "description": "Number of drafts that failed to publish" + }, + "git_synced": { + "type": "boolean", + "description": "Whether git was synced" + }, + "published_drafts_count": { + "type": "number", + "description": "Number of drafts published" + }, + "success": { + "type": "boolean", + "description": "Whether the merge succeeded" + } + }, + "required": [ + "failed_drafts_count", + "git_synced", + "published_drafts_count", + "success" + ] + }, + "ModelsMergeBranchBody": { + "type": "object", + "properties": { + "commit_message": { + "type": "string", + "description": "Custom commit message for git sync" + }, + "delete_branch": { + "type": "boolean", + "default": false, + "description": "Delete the branch after merging" + }, + "force_override_git_settings": { + "type": "boolean", + "default": false, + "description": "Override PR-required or git-follower settings" + }, + "publish_drafts": { + "type": "boolean", + "default": true, + "description": "Publish branch-attached drafts" + } + } + }, + "ModelsCommitResponse": { + "type": "object", + "properties": { + "did_sync": { + "type": "boolean", + "description": "Whether a sync operation was performed against git" + }, + "git_sha": { + "type": [ + "string", + "null" + ], + "description": "The git SHA of the commit that was pushed (null if no commit was needed)" + }, + "in_sync": { + "type": "boolean", + "description": "Whether the branch is in sync with git after the operation" + }, + "pr_url": { + "type": [ + "string", + "null" + ], + "description": "The URL of the pull request (or PR creation page for newly-created PRs). May be null when the underlying git provider is not recognized." + } + }, + "required": [ + "did_sync", + "git_sha", + "in_sync", + "pr_url" + ] + }, + "ModelsCommitBody": { + "type": "object", + "properties": { + "allow_branch_exists": { + "type": "boolean", + "default": true, + "description": "If true (default), the commit succeeds whether the git branch already exists or not. If false, the request fails when the git branch already exists — use this to ensure only new pull requests are created. Cannot be false when require_branch_exists is true.", + "example": true + }, + "branch_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the branch to commit.", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "commit_message": { + "type": "string", + "minLength": 1, + "description": "Commit message for the git commit.", + "example": "Add new orders view" + }, + "require_branch_exists": { + "type": "boolean", + "default": false, + "description": "If true, the request fails when the git branch does not already exist — use this to ensure only existing pull requests are updated. Defaults to false. Cannot be true when allow_branch_exists is false.", + "example": false + } + }, + "required": [ + "branch_id", + "commit_message" + ] + }, + "ModelsCacheResetResponse": { + "type": "object", + "properties": { + "cache_reset": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "Creation timestamp" + }, + "model_id": { + "type": "string", + "description": "Model ID" + }, + "policy_name": { + "type": "string", + "description": "Cache policy name" + }, + "reset_at": { + "type": [ + "string", + "null" + ], + "description": "Reset timestamp" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "Last update timestamp" + } + }, + "required": [ + "created_at", + "model_id", + "policy_name", + "reset_at", + "updated_at" + ], + "description": "Cache reset details" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + } + }, + "required": [ + "cache_reset", + "success" + ] + }, + "ModelsCacheResetBody": { + "type": "object", + "properties": { + "resetAt": { + "type": "string", + "description": "ISO-8601 timestamp for when to reset the cache", + "example": "2024-01-15T12:00:00Z" + } + } + }, + "ModelsGitGetResponse": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" + }, + "baseBranch": { + "type": "string", + "description": "The target branch for Omni pull requests", + "example": "main" + }, + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false + }, + "cloneUrl": { + "type": "string", + "description": "Clone URL of the git repository (SSH or HTTPS)", + "example": "git@github.com:org/repo.git" + }, + "gitFollower": { + "type": "boolean", + "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", + "example": false + }, + "gitServiceProvider": { + "type": "string", + "description": "The git provider type", + "example": "github" + }, + "modelPath": { + "type": [ + "string", + "null" + ], + "description": "Path to model files in the repository", + "example": "omni/my_model" + }, + "publicKey": { + "type": [ + "string", + "null" + ], + "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", + "example": "ssh-ed25519 AAAA..." + }, + "requirePullRequest": { + "type": "string", + "enum": [ + "always", + "users-only", + "never" + ], + "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", + "example": "users-only" + }, + "sshUrl": { + "type": "string", + "deprecated": true, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository." + }, + "webUrl": { + "type": [ + "string", + "null" + ], + "description": "Custom web URL for the git repository, or null if not set", + "example": "https://github.com/org/repo" + }, + "webhookSecret": { + "type": "string", + "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" + }, + "webhookUrl": { + "type": "string", + "description": "Webhook URL to configure in your git provider", + "example": "https://app.omni.co/api/webhooks/model/..." + } + }, + "required": [ + "authMethod", + "baseBranch", + "branchPerPullRequest", + "cloneUrl", + "gitFollower", + "gitServiceProvider", + "modelPath", + "publicKey", + "requirePullRequest", + "sshUrl", + "webUrl", + "webhookUrl" + ] + }, + "ModelsGitCreateResponse": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" + }, + "baseBranch": { + "type": "string", + "description": "The target branch for Omni pull requests", + "example": "main" + }, + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false + }, + "cloneUrl": { + "type": "string", + "description": "Clone URL of the git repository (SSH or HTTPS)", + "example": "git@github.com:org/repo.git" + }, + "gitFollower": { + "type": "boolean", + "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", + "example": false + }, + "gitServiceProvider": { + "type": "string", + "description": "The git provider type", + "example": "github" + }, + "modelPath": { + "type": [ + "string", + "null" + ], + "description": "Path to model files in the repository", + "example": "omni/my_model" + }, + "publicKey": { + "type": [ + "string", + "null" + ], + "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", + "example": "ssh-ed25519 AAAA..." + }, + "requirePullRequest": { + "type": "string", + "enum": [ + "always", + "users-only", + "never" + ], + "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", + "example": "users-only" + }, + "sshUrl": { + "type": "string", + "deprecated": true, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository." + }, + "webUrl": { + "type": [ + "string", + "null" + ], + "description": "Custom web URL for the git repository, or null if not set", + "example": "https://github.com/org/repo" + }, + "webhookSecret": { + "type": "string", + "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" + }, + "webhookUrl": { + "type": "string", + "description": "Webhook URL to configure in your git provider", + "example": "https://app.omni.co/api/webhooks/model/..." + } + }, + "required": [ + "authMethod", + "baseBranch", + "branchPerPullRequest", + "cloneUrl", + "gitFollower", + "gitServiceProvider", + "modelPath", + "publicKey", + "requirePullRequest", + "sshUrl", + "webUrl", + "webhookUrl" + ] + }, + "ModelsGitCreateBody": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" + ], + "default": "ssh", + "description": "Authentication method. \"ssh\" for deploy key (default), \"https_token\" for deploy token/PAT.", + "example": "ssh" + }, + "baseBranch": { + "type": "string", + "default": "main", + "description": "The target branch for Omni pull requests. Defaults to \"main\"", + "example": "main" + }, + "branchPerPullRequest": { + "type": "boolean", + "default": false, + "description": "If true, all pull requests will create a branch in Omni. Defaults to false", + "example": false + }, + "cloneUrl": { + "type": "string", + "minLength": 1, + "description": "Clone URL of the git repository. SSH (git@...) for deploy key auth, HTTPS (https://...) for token auth.", + "example": "git@github.com:org/repo.git" + }, + "gitFollower": { + "type": "boolean", + "default": false, + "description": "If true, the shared model will be read-only. Defaults to false", + "example": false + }, + "gitServiceProvider": { + "type": "string", + "enum": [ + "github", + "gitlab", + "azure_devops", + "bitbucket", + "bitbucket_datacenter", + "auto" + ], + "default": "auto", + "description": "The git provider type. Use \"auto\" for automatic detection. Defaults to \"auto\"", + "example": "auto" + }, + "modelPath": { + "type": "string", + "description": "Path to model files in the repository. Defaults to omni/. Use a plain name (e.g., \"my_model\") for omni/my_model, or a leading slash for a custom path (e.g., \"/bi/models/sales\")", + "example": "my_model" + }, + "requirePullRequest": { + "type": "string", + "enum": [ + "always", + "users-only", + "never" + ], + "default": "never", + "description": "Controls when pull requests are required. Defaults to \"never\"", + "example": "never" + }, + "sshUrl": { + "type": "string", + "minLength": 1, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository.", + "example": "git@github.com:org/repo.git", + "deprecated": true + }, + "token": { + "type": "string", + "maxLength": 1000, + "pattern": "^[a-zA-Z0-9_\\-.]+$", + "description": "HTTPS token for authentication (deploy token value, PAT, etc.). Required when authMethod is \"https_token\"." + }, + "webUrl": { + "type": "string", + "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", + "example": "https://github.com/org/repo" + } + } + }, + "ModelsGitUpdateResponse": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" + }, + "baseBranch": { + "type": "string", + "description": "The target branch for Omni pull requests", + "example": "main" + }, + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false + }, + "cloneUrl": { + "type": "string", + "description": "Clone URL of the git repository (SSH or HTTPS)", + "example": "git@github.com:org/repo.git" + }, + "gitFollower": { + "type": "boolean", + "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", + "example": false + }, + "gitServiceProvider": { + "type": "string", + "description": "The git provider type", + "example": "github" + }, + "modelPath": { + "type": [ + "string", + "null" + ], + "description": "Path to model files in the repository", + "example": "omni/my_model" + }, + "publicKey": { + "type": [ + "string", + "null" + ], + "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", + "example": "ssh-ed25519 AAAA..." + }, + "requirePullRequest": { + "type": "string", + "enum": [ + "always", + "users-only", + "never" + ], + "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", + "example": "users-only" + }, + "sshUrl": { + "type": "string", + "deprecated": true, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository." + }, + "webUrl": { + "type": [ + "string", + "null" + ], + "description": "Custom web URL for the git repository, or null if not set", + "example": "https://github.com/org/repo" + }, + "webhookSecret": { + "type": "string", + "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" + }, + "webhookUrl": { + "type": "string", + "description": "Webhook URL to configure in your git provider", + "example": "https://app.omni.co/api/webhooks/model/..." + } + }, + "required": [ + "authMethod", + "baseBranch", + "branchPerPullRequest", + "cloneUrl", + "gitFollower", + "gitServiceProvider", + "modelPath", + "publicKey", + "requirePullRequest", + "sshUrl", + "webUrl", + "webhookUrl" + ] + }, + "ModelsGitUpdateBody": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method to change to.", + "example": "ssh" + }, + "baseBranch": { + "type": "string", + "description": "The target branch for Omni pull requests", + "example": "main" + }, + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni", + "example": false + }, + "cloneUrl": { + "type": "string", + "minLength": 1, + "description": "Clone URL of the git repository (SSH or HTTPS).", + "example": "git@github.com:org/repo.git" + }, + "gitFollower": { + "type": "boolean", + "description": "If true, the shared model will be read-only", + "example": false + }, + "gitServiceProvider": { + "type": "string", + "enum": [ + "github", + "gitlab", + "azure_devops", + "bitbucket", + "bitbucket_datacenter", + "auto" + ], + "description": "The git provider type", + "example": "github" + }, + "modelPath": { + "type": "string", + "description": "Path to model files in the repository", + "example": "my_model" + }, + "requirePullRequest": { + "type": "string", + "enum": [ + "always", + "users-only", + "never" + ], + "description": "Controls when pull requests are required", + "example": "users-only" + }, + "sshUrl": { + "type": "string", + "minLength": 1, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository.", + "example": "git@github.com:org/repo.git", + "deprecated": true + }, + "token": { + "type": "string", + "maxLength": 1000, + "pattern": "^[a-zA-Z0-9_\\-.]+$", + "description": "HTTPS token for authentication (deploy token value, PAT, etc.)." + }, + "webUrl": { + "type": "string", + "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", + "example": "https://github.com/org/repo" + } + } + }, + "ModelsGitDeleteResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "Git repository unlinked successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ] + }, + "ModelsGitSyncResponse": { + "type": "object", + "properties": { + "didSync": { + "type": "boolean", + "description": "Whether a sync operation was performed" + }, + "gitSha": { + "type": [ + "string", + "null" + ], + "description": "The git SHA after the sync operation" + }, + "inSync": { + "type": "boolean", + "description": "Whether the model is currently in sync with git" + }, + "message": { + "type": "string", + "description": "Human-readable message about the sync status" + } + }, + "required": [ + "didSync", + "gitSha", + "inSync", + "message" + ] + }, + "ModelsGitSyncBody": { + "type": "object", + "properties": { + "commitMessage": { + "type": "string", + "description": "Optional commit message for the git sync operation", + "example": "Update model schema" + } + } + }, + "ModelsContentValidatorGetResponse": { + "type": "object", + "properties": { + "branch": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "description": "Branch UUID" + }, + "name": { + "type": "string", + "description": "Branch name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Branch info (present if branch_id was specified)" + }, + "content": { + "type": "array", + "items": {}, + "description": "Documents with their validation results" + }, + "model_id": { + "type": "string", + "description": "Model UUID" + } + }, + "required": [ + "branch", + "content", + "model_id" + ] + }, + "ContentFilterMode": { + "type": "string", + "enum": [ + "ALL", + "WITH_ISSUES", + "NO_ISSUES" + ], + "description": "Filter documents by issue status. ALL (default) returns all documents with at least one query. WITH_ISSUES returns only documents with at least one query issue, dashboard filter issue, or document error. NO_ISSUES returns only documents with zero issues and no document errors." + }, + "ModelsContentValidatorReplaceResponse": { + "type": "object", + "properties": { + "replaced_dashboard_filters_count": { + "type": "integer", + "description": "Number of dashboard filters replaced" + }, + "replaced_documents_count": { + "type": "integer", + "description": "Number of documents modified" + }, + "replaced_input_column_keys_count": { + "type": "integer", + "description": "Number of input columns whose key references were replaced" + }, + "replaced_queries_count": { + "type": "integer", + "description": "Number of queries replaced" + }, + "replaced_workbook_models_count": { + "type": "integer", + "description": "Number of workbook models replaced" + }, + "skipped_pr_required_count": { + "type": "integer", + "description": "Number of documents skipped due to pull request requirements" + } + }, + "required": [ + "replaced_dashboard_filters_count", + "replaced_documents_count", + "replaced_input_column_keys_count", + "replaced_queries_count", + "replaced_workbook_models_count", + "skipped_pr_required_count" + ] + }, + "ModelsContentValidatorReplaceBody": { + "type": "object", + "properties": { + "branch_id": { + "type": "string", + "description": "Optional branch ID" + }, + "creator_id": { + "type": "string", + "format": "uuid", + "description": "Restrict replacement to documents created by this user (user ID). Unknown IDs return 400." + }, + "find": { + "type": "string", + "minLength": 1, + "description": "The string to find" + }, + "find_or_replace_type": { + "type": "string", + "enum": [ + "FIELD", + "TOPIC", + "VIEW" + ], + "description": "Type of find/replace operation." + }, + "folder_paths": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Restrict replacement to documents in matching folder paths (prefix match). Documents with no folder are excluded unless \"\" is specified." + }, + "include_personal_folders": { + "type": "boolean", + "default": false, + "description": "Whether to include personal folders" + }, + "labels": { + "type": "string", + "description": "Comma-separated label names to scope replacement. Unknown labels return 400." + }, + "only_in_workbook_id": { + "type": "string", + "description": "Optional workbook ID to limit the replace scope" + }, + "replacement": { + "type": "string", + "minLength": 1, + "description": "The replacement string" + } + }, + "required": [ + "find", + "find_or_replace_type", + "replacement" + ] + }, + "ModelYamlResponse": { + "type": "object", + "properties": { + "checksums": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Checksums for each file" + }, + "files": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "YAML content for each file" + }, + "version": { + "type": "number", + "description": "Model version number" + }, + "viewNames": { + "type": "object", + "additionalProperties": {}, + "description": "View name mappings" + } + }, + "required": [ + "files", + "version" + ] + }, + "ModelYamlCreateRequestBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Branch ID for branch-aware operations" + }, + "fileName": { + "type": "string", + "minLength": 1, + "description": "File name to create or update" + }, + "mode": { + "type": "string", + "enum": [ + "combined", + "extension", + "staged", + "merged", + "fully-resolved" + ], + "default": "combined", + "description": "IDE mode for YAML operations" + }, + "commitMessage": { + "type": "string", + "description": "Commit message for git sync" + }, + "fetchedAtMillis": { + "type": "number", + "description": "Timestamp when the file was fetched" + }, + "fullyResolved": { + "type": "boolean", + "default": false, + "description": "Treat the posted YAML as fully resolved (with the extends chain expanded). Only valid with mode=combined." + }, + "previousChecksum": { + "type": "string", + "description": "Previous checksum for conflict detection" + }, + "yaml": { + "type": "string", + "description": "YAML content for the file" + } + }, + "required": [ + "fileName", + "yaml" + ], + "additionalProperties": false + }, + "AiAgentActionsResponse": { + "type": "object", + "properties": { + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiAgentAction" + }, + "description": "AI agent actions in display order: sample queries first, then skills. Topic-level entries follow model-level ones, and skills are deduped by id with topic skills winning over model skills." + } + }, + "required": [ + "records" + ] + }, + "AiAgentAction": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "sample", + "skill" + ], + "description": "Source of the entry: `sample` for `sample_queries` (model- or topic-level) and `skill` for `skills` (model- or topic-level).", + "example": "skill" + }, + "label": { + "type": "string", + "description": "Short, human-readable name for the action — chip text in client UIs and the visible \"prompt\" on the answer card.", + "example": "Revenue trends" + }, + "prompt": { + "type": "string", + "description": "Submit this string verbatim as the `prompt` on `POST /api/v1/ai/jobs`. For sample queries this is the raw prompt; for skills it is a pre-formatted wrapper around the skill's input.", + "example": "Skill:\nShow me the recent revenue trends grouped by month…" + } + }, + "required": [ + "kind", + "label", + "prompt" + ] + }, + "QueryRunResponse": { + "type": "object", + "properties": { + "completedQueries": { + "type": "array", + "items": {}, + "description": "Queries that completed synchronously with their results." + }, + "jobIds": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Job IDs for queries running asynchronously. Use /api/v1/query/wait to poll for results.", + "example": [ + "job_abc123", + "job_def456" + ] + }, + "plan": { + "description": "Query execution plan (only present if planOnly is true)." + } + } + }, + "QueryTimeoutResponse": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Error message indicating the query timed out.", + "example": "Query timed out" + }, + "remaining_job_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Job IDs for queries that have not yet completed. Use /api/v1/query/wait to poll for results." + }, + "timed_out": { + "type": "boolean", + "enum": [ + true + ], + "description": "Always true for timeout responses.", + "example": true + } + }, + "required": [ + "detail", + "timed_out" + ] + }, + "QueryRunBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Optional model branch to run the query against. Must belong to the same shared model as the query. When omitted, the query runs against the shared model. Takes precedence over the legacy `?branch_id=` URL query parameter.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "cache": { + "type": "string", + "enum": [ + "disabled", + "normal", + "refresh", + "refresh_all" + ], + "description": "Cache policy for query execution. Controls whether to use cached results.", + "example": "normal" + }, + "environmentConnectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID of the environment to run the query against, overriding the connection environment inherited from the (target) user's session or default. Must be a configured environment of the query model's connection that the user can access.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "formatResults": { + "type": "boolean", + "description": "Whether to format result values (e.g., apply number formatting). Only valid when resultType is specified." + }, + "planOnly": { + "type": "boolean", + "default": false, + "description": "If true, returns only the query execution plan without running the query." + }, + "query": { + "description": "The semantic query definition including fields, filters, sorts, and other query parameters." + }, + "resultType": { + "type": "string", + "enum": [ + "csv", + "json", + "xlsx" + ], + "description": "Output format for the results. If not specified, returns base64-encoded Arrow format." + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "Alternate location for the `?userId=` query parameter. Prefer the query parameter — this body field exists for backwards compatibility. Supplying both forms results in a 400. Only valid for org-scoped API keys; when set, the user's attributes are applied for row-level security and connection-environment switching.", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + } + }, + "QueryWaitResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": {}, + "description": "Array of completed query results. Each result contains the query data or an error." + } + }, + "required": [ + "results" + ] + }, + "SchedulesListItem": { + "type": "object", + "properties": { + "alert": { + "type": "object", + "properties": { + "conditionQueryName": { + "type": [ + "string", + "null" + ], + "description": "Name of the query used for alert condition" + }, + "conditionType": { + "type": "string", + "description": "Type of alert condition: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" + } + }, + "required": [ + "conditionQueryName", + "conditionType" + ], + "description": "Alert configuration (only present for alert-type schedules)" + }, + "content": { + "type": "string", + "description": "Content type: dashboard or tile", + "example": "dashboard" + }, + "dashboardName": { + "type": "string", + "description": "Name of the dashboard", + "example": "Weekly Sales Report" + }, + "destinationType": { + "type": "string", + "description": "Delivery destination type: email, slack, webhook, sftp, s3, google_sheets", + "example": "email" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when the schedule was paused (null if active)" + }, + "format": { + "type": "string", + "description": "Output format: pdf, png, csv, xlsx, json, link_only", + "example": "pdf" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the schedule" + }, + "identifier": { + "type": "string", + "description": "Dashboard identifier", + "example": "12db1a0a" + }, + "lastCompletedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp of last completed delivery" + }, + "lastStatus": { + "type": [ + "string", + "null" + ], + "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" + }, + "name": { + "type": "string", + "description": "Name of the schedule", + "example": "Weekly Sales Report" + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the schedule owner" + }, + "ownerName": { + "type": "string", + "description": "Display name of the schedule owner", + "example": "John Doe" + }, + "recipientCount": { + "type": "number", + "description": "Number of recipients (-1 for non-email destinations)", + "example": 5 + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", + "example": "0 9 ? * MON *" + }, + "slackRecipientType": { + "type": [ + "string", + "null" + ], + "description": "Slack recipient type: Channel or Users (null for non-Slack)" + }, + "systemDisabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when system disabled the schedule (null if not system-disabled)" + }, + "systemDisabledReason": { + "type": [ + "string", + "null" + ], + "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for the schedule", + "example": "America/New_York" + } + }, + "required": [ + "content", + "dashboardName", + "destinationType", + "disabledAt", + "format", + "id", + "identifier", + "lastCompletedAt", + "lastStatus", + "name", + "ownerId", + "ownerName", + "recipientCount", + "schedule", + "slackRecipientType", + "systemDisabledAt", + "systemDisabledReason", + "timezone" + ] + }, + "SchedulesGetResponse": { + "type": "object", + "properties": { + "conditionQueryMapKey": { + "type": [ + "string", + "null" + ], + "description": "Query key used for alert condition (null for standard schedules)" + }, + "conditionType": { + "type": [ + "string", + "null" + ], + "description": "Alert condition type: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "Creation timestamp" + }, + "destinations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SchedulesGetDestination" + }, + "description": "Delivery destination configurations" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when the schedule was paused (null if active)" + }, + "entityId": { + "type": "string", + "description": "ID of the associated dashboard" + }, + "fanOut": { + "type": "boolean", + "description": "Whether personalized fan-out delivery is enabled", + "example": false + }, + "filterConfig": { + "description": "The effective dashboard filter configuration that the schedule will run with: the dashboard's current default filters merged under the schedule's persisted overrides, with any keys no longer present on the dashboard dropped. This matches what is shown when the schedule is opened in the Edit Delivery panel, and may differ from the schedule's persisted filter configuration." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Schedule UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "killJobsOnFailure": { + "type": "boolean", + "description": "Whether to stop the job if any queries fail", + "example": false + }, + "metadata": { + "description": "Schedule metadata including format options and delivery settings. Includes `timezoneOverride` (IANA timezone applied to query execution at render time, or null when no override is set)." + }, + "name": { + "type": "string", + "description": "Schedule name", + "example": "Weekly Sales Report" + }, + "organizationId": { + "type": "string", + "format": "uuid", + "description": "Organization UUID" + }, + "owner": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Schedule owner name" + } + }, + "required": [ + "name" + ] + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the schedule owner" + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", + "example": "0 9 ? * MON *" + }, + "systemDisabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when the system disabled the schedule" + }, + "systemDisabledReason": { + "type": [ + "string", + "null" + ], + "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for the schedule", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp" + } + }, + "required": [ + "conditionQueryMapKey", + "conditionType", + "createdAt", + "destinations", + "disabledAt", + "entityId", + "fanOut", + "id", + "killJobsOnFailure", + "name", + "organizationId", + "owner", + "ownerId", + "schedule", + "systemDisabledAt", + "systemDisabledReason", + "timezone", + "updatedAt" + ] + }, + "SchedulesGetDestination": { + "type": "object", + "properties": { + "format": { + "type": "string", + "description": "Output format: pdf, png, csv, xlsx, json, link_only", + "example": "pdf" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Destination UUID" + }, + "lastCompletedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp of last completed delivery" + }, + "lastStatus": { + "type": [ + "string", + "null" + ], + "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" + }, + "metadata": { + "description": "Destination-specific configuration (type, recipients, credentials, etc.)" + }, + "recipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SchedulesGetRecipient" + }, + "description": "Individual email recipients" + }, + "userGroupRecipients": { + "type": "array", + "items": {}, + "description": "User group recipients" + } + }, + "required": [ + "format", + "id", + "lastCompletedAt", + "lastStatus", + "recipients", + "userGroupRecipients" + ] + }, + "SchedulesGetRecipient": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Recipient ID" + }, + "membership": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Recipient email" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Recipient name" + } + }, + "required": [ + "email", + "name" + ] + } + }, + "required": [ + "user" + ] + }, + "membershipId": { + "type": "string", + "format": "uuid", + "description": "Membership ID" + } + }, + "required": [ + "id", + "membership", + "membershipId" + ] + }, + "SchedulesRecipientsGetResponse": { + "type": "object", + "properties": { + "recipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmailRecipient" + }, + "description": "List of individual recipients (for email destinations)." + }, + "type": { + "type": "string", + "enum": [ + "email", + "google_sheets", + "s3", + "sftp", + "slack", + "webhook" + ], + "description": "The schedule's destination type.", + "example": "email" + }, + "userGroupRecipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserGroupRecipient" + }, + "description": "List of user group recipients (for email destinations)." + } + }, + "required": [ + "type" + ] + }, + "EmailRecipient": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Recipient's email address.", + "example": "user@example.com" + }, + "id": { + "type": "string", + "description": "Unique identifier for the recipient." + }, + "name": { + "type": "string", + "description": "Recipient's display name.", + "example": "John Doe" + } + }, + "required": [ + "email", + "id", + "name" + ] + }, + "UserGroupRecipient": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "User group ID." + }, + "name": { + "type": "string", + "description": "User group name.", + "example": "Sales Team" + }, + "recipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmailRecipient" + }, + "description": "List of recipients in the user group." + } + }, + "required": [ + "id", + "name", + "recipients" + ] + }, + "SchedulesAddRecipientsResponse": { + "type": "object", + "properties": { + "addedGroupRecipientsCount": { + "type": "number", + "description": "Number of user group recipients added.", + "example": 1 + }, + "addedRecipientsCount": { + "type": "number", + "description": "Number of individual recipients added.", + "example": 2 + }, + "success": { + "type": "boolean", + "description": "Whether the operation was successful.", + "example": true + } + }, + "required": [ + "addedGroupRecipientsCount", + "addedRecipientsCount", + "success" + ] + }, + "SchedulesAddRecipientsBody": { + "type": "object", + "properties": { + "emails": { + "type": "array", + "items": { + "type": "string", + "format": "email" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of email addresses to add as recipients.", + "example": [ + "user@example.com" + ] + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to add as recipients.", + "example": [ + "123e4567-e89b-12d3-a456-426614174000" + ] + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of user UUIDs to add as recipients. Use the List users and List embed users endpoints to retrieve user IDs.", + "example": [ + "987fcdeb-51a2-43d7-9b56-254415f67890" + ] + } + } + }, + "SchedulesRemoveRecipientsResponse": { + "type": "object", + "properties": { + "removedGroupRecipientsCount": { + "type": "number", + "description": "Number of user group recipients removed.", + "example": 1 + }, + "removedRecipientsCount": { + "type": "number", + "description": "Number of individual recipients removed.", + "example": 2 + }, + "success": { + "type": "boolean", + "description": "Whether the operation was successful.", + "example": true + } + }, + "required": [ + "removedGroupRecipientsCount", + "removedRecipientsCount", + "success" + ] + }, + "SchedulesRemoveRecipientsBody": { + "type": "object", + "properties": { + "emails": { + "type": "array", + "items": { + "type": "string", + "format": "email" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of recipient email addresses to remove from the scheduled task.", + "example": [ + "user@example.com" + ] + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to remove as recipients.", + "example": [ + "123e4567-e89b-12d3-a456-426614174000" + ] + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of recipient user UUIDs to remove from the scheduled task. Use the List users and List embed users endpoints to retrieve user IDs.", + "example": [ + "987fcdeb-51a2-43d7-9b56-254415f67890" + ] + } + } + }, + "SchedulesTransferOwnershipBody": { + "type": "object", + "properties": { + "userId": { + "type": "string", + "format": "uuid", + "description": "The UUID of the user to transfer schedule ownership to. Use the List users endpoint to retrieve user IDs. The new owner must be a member of the same organization, not be the current owner, and have permission to view the dashboard associated with the schedule.", + "example": "987fcdeb-51a2-43d7-9b56-254415f67890" + } + }, + "required": [ + "userId" + ] + }, + "ScimUsersListResponse": { + "type": "object", + "properties": { + "Resources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScimUserResponse" + }, + "description": "List of SCIM users" + }, + "itemsPerPage": { + "type": "number", + "description": "Items per page" + }, + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "SCIM schema URIs" + }, + "startIndex": { + "type": "number", + "description": "Start index (1-based)" + }, + "totalResults": { + "type": "number", + "description": "Total number of results" + } + }, + "required": [ + "Resources", + "itemsPerPage", + "schemas", + "startIndex", + "totalResults" + ] + }, + "ScimUserResponse": { + "type": "object", + "properties": { + "active": { + "type": "boolean", + "description": "Whether the user is active" + }, + "displayName": { + "type": "string", + "description": "Display name" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID" + }, + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "SCIM schema URIs" + }, + "userName": { + "type": "string", + "format": "email", + "description": "Username (email)" + } + }, + "required": [ + "active", + "displayName", + "id", + "schemas", + "userName" + ] + }, + "ScimUserCreateRequest": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "Display name of the user", + "example": "John Doe" + }, + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + }, + "description": "Omni user attributes" + }, + "userName": { + "type": "string", + "format": "email", + "description": "Email address (username) of the user", + "example": "user@example.com" + } + }, + "required": [ + "displayName", + "userName" + ] + }, + "ScimUserPutRequest": { + "type": "object", + "properties": { + "active": { + "type": "boolean", + "default": true, + "description": "Whether the user is active" + }, + "displayName": { + "type": "string", + "description": "Display name of the user" + }, + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + }, + "description": "Enterprise SCIM user attributes" + }, + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + }, + "description": "Omni user attributes" + }, + "userName": { + "type": "string", + "format": "email", + "description": "Email address (username) of the user", + "example": "user@example.com" + } + }, + "required": [ + "userName" + ] + }, + "ScimUserPatchRequest": { + "type": "object", + "properties": { + "Operations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "replace", + "Replace", + "add", + "Add", + "Remove", + "remove" + ] + }, + "path": { + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + } + }, + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + } + }, + "active": { + "type": "boolean" + }, + "displayName": { + "type": "string" + }, + "userName": { + "type": "string", + "format": "email" + } + } + } + ] + } + }, + "required": [ + "op", + "value" + ] + }, + "minItems": 1, + "description": "List of patch operations to apply" + }, + "schemas": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "urn:ietf:params:scim:api:messages:2.0:PatchOp" + ] + }, + "description": "SCIM schema URIs" + } + }, + "required": [ + "Operations", + "schemas" + ] + }, + "ScimGroupsListResponse": { + "type": "object", + "properties": { + "Resources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScimGroupResponse" + }, + "description": "List of SCIM groups" + }, + "itemsPerPage": { + "type": "number", + "description": "Items per page" + }, + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "SCIM schema URIs" + }, + "startIndex": { + "type": "number", + "description": "Start index (1-based)" + }, + "totalResults": { + "type": "number", + "description": "Total number of results" + } + }, + "required": [ + "Resources", + "itemsPerPage", + "schemas", + "startIndex", + "totalResults" + ] + }, + "ScimGroupResponse": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "Group display name" + }, + "id": { + "type": "string", + "description": "SCIM group ID (miniUuid)" + }, + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Member display name" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "Member user ID" + } + }, + "required": [ + "display", + "value" + ] + }, + "description": "Group members" + }, + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "SCIM schema URIs" + } + }, + "required": [ + "displayName", + "id", + "schemas" + ] + }, + "ScimGroupsCreateBody": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "Display name of the group", + "example": "Engineering Team" + }, + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "value" + ] + }, + "default": [], + "description": "List of group members" + } + }, + "required": [ + "displayName" + ] + }, + "ScimGroupsReplaceBody": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "Display name of the group", + "example": "Engineering Team" + }, + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Display name of the member", + "example": "john.doe@example.com" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "display", + "value" + ] + }, + "description": "List of group members" + } + }, + "required": [ + "displayName", + "members" + ] + }, + "ScimGroupsPatchBody": { + "type": "object", + "properties": { + "Operations": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "replace", + "Replace" + ], + "description": "Operation type", + "example": "replace" + }, + "value": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "New display name", + "example": "Engineering Team" + }, + "id": { + "type": "string", + "description": "Group ID" + } + }, + "required": [ + "displayName" + ] + } + }, + "required": [ + "op", + "value" + ] + }, + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "remove", + "Remove" + ], + "description": "Operation type", + "example": "remove" + }, + "path": { + "type": "string", + "pattern": "members\\[value eq \"(.{36})\"\\]", + "description": "SCIM path for member to remove", + "example": "members[value eq \"550e8400-e29b-41d4-a716-446655440000\"]" + } + }, + "required": [ + "op", + "path" + ] + }, + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "add", + "Add" + ], + "description": "Operation type", + "example": "add" + }, + "path": { + "type": "string", + "enum": [ + "members" + ], + "description": "Path for members", + "example": "members" + }, + "value": { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Display name of the member", + "example": "john.doe@example.com" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "value" + ] + } + } + }, + "required": [ + "op", + "path", + "value" + ] + }, + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "replace", + "Replace" + ], + "description": "Operation type", + "example": "replace" + }, + "path": { + "type": "string", + "enum": [ + "members", + "displayName" + ], + "description": "Path for attribute to replace", + "example": "members" + }, + "value": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Display name of the member", + "example": "john.doe@example.com" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "value" + ] + } + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "op", + "path", + "value" + ] + } + ] + }, + "description": "List of SCIM patch operations" + }, + "schemas": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "urn:ietf:params:scim:api:messages:2.0:PatchOp" + ] + }, + "description": "SCIM schema URIs" + } + }, + "required": [ + "Operations", + "schemas" + ] + }, + "DocumentExportResponse": { + "type": "object", + "properties": { + "dashboard": { + "description": "Dashboard configuration and layout" + }, + "document": { + "type": "object", + "properties": { + "ephemeral": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "exportVersion": { + "type": "string" + }, + "fileUploads": { + "type": "object", + "additionalProperties": {} + }, + "queryModels": { + "type": "object", + "additionalProperties": {} + }, + "workbookModel": {} + }, + "required": [ + "document", + "exportVersion", + "queryModels" + ] + }, + "DocumentImportResponse": { + "type": "object", + "properties": { + "documentId": { + "type": "string", + "format": "uuid", + "description": "ID of the imported document" + }, + "identifier": { + "type": "string", + "description": "Document identifier (miniUuid)" + } + }, + "required": [ + "documentId", + "identifier" + ] + }, + "DocumentImportBody": { + "type": "object", + "properties": { + "baseModelId": { + "type": "string", + "format": "uuid", + "description": "Base model ID for the imported document" + }, + "dashboard": { + "description": "Dashboard export data" + }, + "document": { + "type": "object", + "properties": { + "ephemeral": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "exportVersion": { + "type": "string", + "enum": [ + "0.1" + ] + }, + "fileUploads": { + "type": "object", + "additionalProperties": {} + }, + "folderPath": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "queryModels": { + "type": "object", + "additionalProperties": {} + }, + "workbookModel": {} + }, + "required": [ + "baseModelId", + "document", + "exportVersion", + "queryModels" + ] + }, + "UserAttributesListResponse": { + "type": "object", + "properties": { + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "default_value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + { + "type": "null" + } + ], + "description": "Default value applied when no user-specific value is set. When multiple_values is true, this is an array. Null if no default is configured.", + "example": "us-east" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Human-readable description of the attribute and its purpose", + "example": "User region for row-level security filtering" + }, + "id": { + "type": "string", + "description": "Unique identifier for custom attributes. Empty string for system-defined attributes.", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "label": { + "type": "string", + "description": "Display name shown in the Omni UI", + "example": "Region" + }, + "multiple_values": { + "type": "boolean", + "description": "Whether the attribute accepts an array of values. When true, default_value and user-specific values are arrays.", + "example": false + }, + "name": { + "type": "string", + "description": "Reference name used in model SQL and in embed SSO URL parameters", + "example": "region" + }, + "system": { + "type": "boolean", + "description": "System-defined attributes (e.g. omni_user_id, omni_user_email) are built-in and read-only. Custom attributes have system=false.", + "example": false + }, + "type": { + "type": "string", + "enum": [ + "String", + "Number" + ], + "description": "Data type that determines valid values. String attributes accept text, Number attributes accept numeric values stored as strings for precision.", + "example": "String" + } + }, + "required": [ + "default_value", + "description", + "id", + "label", + "multiple_values", + "name", + "system", + "type" + ] + }, + "description": "All user attribute definitions in the organization, including both system-defined and custom attributes" + } + }, + "required": [ + "records" + ] + }, + "UploadsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Upload" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "Upload": { + "type": "object", + "properties": { + "connection_id": { + "type": "string", + "format": "uuid", + "description": "Connection ID the upload is associated with" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "When the file was uploaded" + }, + "file_name": { + "type": "string", + "description": "Original file name", + "example": "users.csv" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the upload" + }, + "in_db_as_table_name": { + "type": [ + "string", + "null" + ], + "description": "Database table name if uploaded to database scratch schema" + }, + "model_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Model ID the upload is associated with (inferred from connection's shared model if not explicitly set)" + }, + "size_bytes": { + "type": [ + "number", + "null" + ], + "description": "File size in bytes" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp" + }, + "uploaded_by_user": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "User ID of the uploader" + }, + "name": { + "type": "string", + "description": "Name of the user who uploaded the file" + } + }, + "required": [ + "id", + "name" + ], + "description": "User who uploaded the file" + }, + "view_name": { + "type": "string", + "description": "View name associated with the upload" + } + }, + "required": [ + "connection_id", + "created_at", + "file_name", + "id", + "in_db_as_table_name", + "model_id", + "size_bytes", + "updated_at", + "uploaded_by_user", + "view_name" + ] + }, + "UploadCreateResponse": { + "type": "object", + "properties": { + "fileName": { + "type": "string", + "description": "Original file name", + "example": "users.csv" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the upload" + }, + "inDbAsTableName": { + "type": "string", + "description": "Database table name in the scratch schema" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID the view was created in" + }, + "rowCount": { + "type": "integer", + "description": "Number of rows in the uploaded file" + }, + "truncated": { + "type": "boolean", + "description": "Whether the file was truncated due to row limit" + }, + "viewCreated": { + "type": "boolean", + "description": "Whether a view was created in the model" + }, + "viewName": { + "type": "string", + "description": "Name of the view created" + } + }, + "required": [ + "fileName", + "id", + "inDbAsTableName", + "modelId", + "rowCount", + "truncated", + "viewCreated", + "viewName" + ] + }, + "UploadCreateBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "UUID of the branch to create the view in (mutually exclusive with branchName)" + }, + "branchName": { + "type": "string", + "description": "Name of the branch to create the view in (mutually exclusive with branchId)" + }, + "file": { + "type": "string", + "description": "The CSV file to upload", + "format": "binary" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "UUID of the model to create the view in" + }, + "viewName": { + "type": "string", + "description": "Override the view name (defaults to sanitized file name)" + } + }, + "required": [ + "file", + "modelId" + ] + }, + "UploadDeleteResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the deletion was successful" + } + }, + "required": [ + "success" + ] + }, + "UsersGetModelRolesResponse": { + "type": "object", + "properties": { + "membershipId": { + "type": "string", + "format": "uuid", + "description": "The user membership ID" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoleAssignmentResult" + }, + "description": "List of role assignments" + } + }, + "required": [ + "membershipId", + "results" + ] + }, + "RoleAssignmentResult": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "The base role definition name", + "example": "VIEWER" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection this role applies to" + }, + "from": { + "$ref": "#/components/schemas/RoleOrigin" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model this role applies to" + }, + "priority": { + "type": "number", + "description": "Priority for role resolution (higher = more permissive)" + }, + "resolved": { + "type": "boolean", + "description": "Whether this is the resolved (effective) role" + }, + "roleName": { + "type": "string", + "description": "The role name (base or custom)", + "example": "VIEWER" + } + }, + "required": [ + "baseRole", + "connectionId", + "from", + "modelId", + "priority", + "resolved", + "roleName" + ] + }, + "RoleOrigin": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "USER" + ], + "description": "Role assigned directly to user" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "ORG" + ], + "description": "Role inherited from organization" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "BASE" + ], + "description": "Connection base role" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "depth": { + "type": "number", + "description": "Nesting depth of the group" + }, + "miniUuid": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "name": { + "type": "string", + "description": "Name of the group", + "example": "Engineering Team" + }, + "type": { + "type": "string", + "enum": [ + "GROUP" + ], + "description": "Role inherited from group membership" + } + }, + "required": [ + "depth", + "miniUuid", + "name", + "type" + ] + } + ], + "description": "Origin of this role assignment" + }, + "UsersAssignModelRoleResponse": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "The connection ID for this role assignment" + }, + "membershipId": { + "type": "string", + "format": "uuid", + "description": "The user membership ID" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The model ID for this role assignment" + }, + "roleName": { + "type": "string", + "description": "The assigned role name", + "example": "VIEWER" + } + }, + "required": [ + "connectionId", + "membershipId", + "modelId", + "roleName" + ] + }, + "UsersAssignModelRoleBody": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID for model-level role assignment. Required if connectionId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "roleName": { + "type": "string", + "minLength": 1, + "description": "Name of the role to assign (base or custom role)", + "example": "VIEWER" + } + }, + "required": [ + "roleName" + ] + }, + "UsersListEmailOnlyResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "User email address", + "example": "user@example.com" + }, + "user_attributes": { + "type": "object", + "additionalProperties": {}, + "description": "User attributes as key-value pairs" + }, + "user_id": { + "type": "string", + "format": "uuid", + "description": "User ID" + } + }, + "required": [ + "email", + "user_attributes", + "user_id" + ] + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "UsersCreateEmailOnlyResponse": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address of the created user", + "example": "user@example.com" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "ID of the created user" + } + }, + "required": [ + "email", + "userId" + ] + }, + "UsersCreateEmailOnlyBody": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address for the user", + "example": "user@example.com" + }, + "userAttributes": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "description": "Optional user attributes as key-value pairs" + } + }, + "required": [ + "email" + ] + }, + "UsersCreateEmailOnlyBulkResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address of the created user", + "example": "user@example.com" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "ID of the created user" + } + }, + "required": [ + "email", + "userId" + ] + }, + "description": "Results for each created user" + } + }, + "required": [ + "results" + ] + }, + "UsersCreateEmailOnlyBulkBody": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address for the user", + "example": "user@example.com" + }, + "userAttributes": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "description": "Optional user attributes as key-value pairs" + } + }, + "required": [ + "email" + ] + }, + "minItems": 1, + "maxItems": 20, + "description": "Array of users to create (1-20 users)" + } + }, + "required": [ + "users" + ] + }, + "UserGroupsGetModelRolesResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserGroupRoleAssignmentResult" + }, + "description": "List of role assignments" + }, + "userGroupId": { + "type": "string", + "description": "The user group short identifier", + "example": "abc123" + } + }, + "required": [ + "results", + "userGroupId" + ] + }, + "UserGroupRoleAssignmentResult": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "The base role definition name", + "example": "VIEWER" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection this role applies to" + }, + "from": { + "$ref": "#/components/schemas/UserGroupRoleOrigin" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model this role applies to" + }, + "priority": { + "type": "number", + "description": "Priority for role resolution (higher = more permissive)" + }, + "roleName": { + "type": "string", + "description": "The role name (base or custom)", + "example": "VIEWER" + } + }, + "required": [ + "baseRole", + "connectionId", + "from", + "modelId", + "priority", + "roleName" + ] + }, + "UserGroupRoleOrigin": { + "type": "object", + "properties": { + "depth": { + "type": "number", + "description": "Nesting depth of the group (0 for direct assignment)" + }, + "miniUuid": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "name": { + "type": "string", + "description": "Name of the group", + "example": "Engineering Team" + }, + "type": { + "type": "string", + "enum": [ + "GROUP" + ], + "description": "Role assigned to group" + } + }, + "required": [ + "depth", + "miniUuid", + "name", + "type" + ], + "description": "Origin of this role assignment" + }, + "UserGroupsAssignModelRoleResponse": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "The connection ID for this role assignment" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The model ID for this role assignment" + }, + "roleName": { + "type": "string", + "description": "The assigned role name", + "example": "VIEWER" + }, + "userGroupId": { + "type": "string", + "description": "The user group short identifier", + "example": "abc123" + } + }, + "required": [ + "connectionId", + "modelId", + "roleName", + "userGroupId" + ] + }, + "UserGroupsAssignModelRoleBody": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID for model-level role assignment. Required if connectionId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "roleName": { + "type": "string", + "minLength": 1, + "description": "Name of the role to assign (base or custom role)", + "example": "VIEWER" + } + }, + "required": [ + "roleName" + ] + }, + "WhoamiResponse": { + "type": "object", + "properties": { + "keyScope": { + "type": "string", + "enum": [ + "user", + "organization" + ], + "description": "Scope of the API key in use. A separate axis from role: a user-scoped key (PAT/OAuth) acts as a single user and cannot use SCIM, regardless of the user's org role." + }, + "orgRole": { + "type": "string", + "enum": [ + "MEMBER", + "ORG_ADMIN" + ], + "description": "The caller's organization role.", + "example": "MEMBER" + }, + "rolesByModel": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/WhoamiModelRole" + }, + "description": "Resolved role and effective permissions per model, keyed by model id. Connection role resolves per shared model, so this is per-model rather than a single global role." + }, + "rolesByModelTruncated": { + "type": "boolean", + "description": "Present and `true` when `rolesByModel` was truncated because the caller can access more models than the unfiltered limit. Pass a `modelId` filter to retrieve specific models." + }, + "user": { + "$ref": "#/components/schemas/WhoamiUser" + } + }, + "required": [ + "keyScope", + "orgRole", + "rolesByModel", + "user" + ] + }, + "WhoamiModelRole": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "The resolved base role (for custom roles, the base role they extend).", + "example": "QUERIER" + }, + "connectionId": { + "type": "string", + "description": "The connection this model belongs to" + }, + "permissions": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "QUERY_FULL_MODEL", + "QUERY_SQL", + "VIEW_SQL", + "QUERY_TOPICS", + "RUN_CONTENT_QUERIES", + "DOWNLOAD_CONTENT_QUERY", + "UPLOAD_CSV", + "SCHEDULE", + "SAVE_SPREADSHEETS", + "USE_AI", + "USE_IDE", + "USE_WORKBOOKS", + "UPDATE", + "UPDATE_RESTRICTED" + ] + }, + "description": "The caller's resolved/effective permissions on this model, reflecting custom roles. This is a capability signal for the directly-roleable model kinds (schema / shared / extension). It does not enumerate the permissions you derive on branch, workbook, and query models from your role on the base model they descend from — absence here does not mean you lack access on those derived models. MANAGE_MODEL, READ, and REFRESH_SCHEMA are also not reported: they derive from connection / sibling-model roles rather than a per-model rule.", + "example": [ + "QUERY_TOPICS", + "QUERY_SQL", + "USE_WORKBOOKS" + ] + }, + "roleName": { + "type": "string", + "description": "The resolved role name (informational; may be a custom role). Use `permissions` to decide capability.", + "example": "QUERIER" + } + }, + "required": [ + "baseRole", + "connectionId", + "permissions", + "roleName" + ] + }, + "WhoamiUser": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The caller's user id" + }, + "membershipId": { + "type": "string", + "description": "The caller's own membership id within this organization. This is the id accepted by the admin `GET /api/v1/users/{id}/model-roles` endpoint (it is distinct from the user id)." + } + }, + "required": [ + "id", + "membershipId" + ] + } + }, + "parameters": {} + }, + "paths": { + "/api/v1/ai/generate-query": { + "post": { + "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model.", + "operationId": "aiGenerateQuery", + "summary": "Generate query from natural language", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiGenerateQueryBody" + } + } + } + }, + "responses": { + "200": { + "description": "Query generated successfully. If runQuery is true (default), includes execution results. Check the error field — a 200 response may still contain a partial error if the query was generated but execution failed. When the organization is over its AI downgrade threshold the response also carries `downgradedModelTier` naming the cheaper tier the query was generated with.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiGenerateQueryResponse" + } + } + } + }, + "400": { + "description": "Invalid request. The prompt may be missing, the modelId may be invalid, or the AI was unable to generate a query for the given prompt.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "402": { + "description": "AI is unavailable because the organization is over its AI credit limit. The body carries the stable reason code `shutoff`.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditShutoffError" + } + } + } + }, + "403": { + "description": "Insufficient permissions. Requires the querier role on the target model and AI query generation must be enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model or topic was not found in the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/pick-topic": { + "post": { + "description": "Analyze a natural language prompt and determine which topic in the model is the best fit for answering the question. Useful as a preprocessing step before calling generate-query or submitting an AI job, especially when the user's question could relate to multiple topics.", + "operationId": "aiPickTopic", + "summary": "Pick the best topic for a prompt", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPickTopicBody" + } + } + } + }, + "responses": { + "200": { + "description": "Topic selected successfully. The returned topicId can be used as the topicName parameter in other AI endpoints.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPickTopicResponse" + } + } + } + }, + "400": { + "description": "Invalid request body. The prompt or modelId may be missing or malformed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. Requires the querier role on the target model and AI must be enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model was not found, or no accessible topics exist in the model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/search-omni-docs": { + "post": { + "description": "Search the Omni documentation using AI to answer questions about Omni features, configuration, modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer with source links to the relevant documentation pages.", + "operationId": "aiSearchOmniDocs", + "summary": "Search Omni documentation", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiSearchOmniDocsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Documentation search completed successfully. Returns a synthesized answer with source links.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiSearchOmniDocsResponse" + } + } + } + }, + "400": { + "description": "Invalid request. The question may be missing or exceed the 2000 character limit.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Omni Agent is not enabled for this organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/jobs": { + "post": { + "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId.", + "operationId": "aiJobSubmit", + "summary": "Submit an AI job", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobSubmitBody" + } + } + } + }, + "responses": { + "201": { + "description": "Job created and queued for execution. Use the returned jobId to poll for status or retrieve results.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobSubmitResponse" + } + } + } + }, + "400": { + "description": "Invalid request body. Common causes: missing or empty prompt, invalid UUID for modelId/branchId/conversationId, invalid webhook URL format.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. The AI jobs API must be enabled for the organization, AI query generation must be enabled, and the user must have appropriate model access. User-scoped API keys cannot act on behalf of other users.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model was not found in the organization, the branchId does not belong to the specified model, or the topicName does not exist in the model (or is excluded by ai_chat_topics restrictions).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "409": { + "description": "An active job already exists for the specified conversationId. Wait for the current job to complete before submitting another job to the same conversation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}": { + "get": { + "description": "Get the current status of an AI job, including its state, progress information, and result summary. The response fields vary by state — for example, progress is only present during EXECUTING, and resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job reaches a terminal state (COMPLETE, FAILED, or CANCELLED).", + "operationId": "aiJobStatus", + "summary": "Get AI job status", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Job status retrieved successfully. Check the state field to determine if the job is still running or has reached a terminal state.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobStatusResponse" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. AI query generation must be enabled for the organization and the caller must have permission to use AI on the job's model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Job not found. The job may not exist or may belong to a different organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/cancel": { + "post": { + "description": "Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING state cannot be cancelled as they are already finalizing results. Only the job owner or organization admins can cancel jobs.", + "operationId": "aiJobCancel", + "summary": "Cancel an AI job", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Cancellation request processed. The state field indicates the job's state after the attempt — CANCELLED if successful, or the current terminal state if the job had already completed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobCancelResponse" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Permission denied. Only the job owner or organization admins can cancel jobs.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Job not found. The job may not exist or may belong to a different organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "409": { + "description": "Concurrent modification conflict. The job state was changed by another request. Retry the cancellation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/result": { + "get": { + "description": "Retrieve the full result of a completed AI job, including all actions taken by the AI (queries generated, data retrieved) and the final summarized answer. Results are only available for jobs in COMPLETE state and are retained for 14 days after completion. The response is streamed directly from storage.", + "operationId": "aiJobResult", + "summary": "Get AI job result", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Full job result including the AI's actions, query results (with CSV data), and the final Markdown-formatted answer.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobResultResponse" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. AI query generation must be enabled for the organization and the caller must have permission to use AI on the job's model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Job not found, not in COMPLETE state, or result is no longer available (results are retained for 14 days).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/vis": { + "get": { + "description": "Render the visualization from a completed AI job as a PNG image. The endpoint extracts the visualization configuration from the job result, loads Arrow IPC data, and renders it server-side using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back through previous jobs in the conversation to find the original query data.", + "operationId": "aiJobVisualization", + "summary": "Render AI job visualization", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Visualization rendered as a PNG image. The Content-Type header is image/png.", + "content": { + "image/png": { + "schema": { + "format": "binary", + "type": "string" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. AI query generation must be enabled for the organization and the caller must have permission to use AI on the job's model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Job not found, not in COMPLETE state, or the apiAiVis feature flag is not enabled.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "422": { + "description": "The job completed but cannot be rendered as a visualization. Common causes: no visualization action in the job result, no Arrow IPC data available, missing summary fields, or the chart type is not renderable as an image (e.g., tables, KPIs).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError422" + } + } + } + } + } + } + }, + "/api/v1/ai/branding": { + "get": { + "description": "Returns the organization's AI helper branding — display name, optional custom logo URL, and copy used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's defaults when the organization hasn't configured custom branding, so the response is always populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity.", + "operationId": "aiBranding", + "summary": "Get AI helper branding", + "tags": [ + "AI" + ], + "responses": { + "200": { + "description": "AI branding retrieved successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiBrandingResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI access is required to view AI helper branding (no model in the org grants USE_AI to the caller).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + } + }, + "/api/v1/ai/conversations": { + "get": { + "description": "List the user's recent AI conversations, ordered by most-recent activity. Each record includes the conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to continue the thread), an optional name, and a one-line summary of the most recent prompt for display. Paginated via opaque `pageInfo.nextCursor` — pass it back as `cursor` to fetch the next page.", + "operationId": "aiConversationsList", + "summary": "List AI conversations", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of conversations.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiConversationsListResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + } + }, + "/api/v1/ai/conversations/{conversationId}": { + "get": { + "description": "Return a conversation with its full message history (alternating user / assistant turns). Used by clients (iOS app, embed widgets) to restore a prior conversation in their UI.", + "operationId": "aiConversationDetail", + "summary": "Get AI conversation with messages", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "conversationId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Conversation with messages in chronological order.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiConversationDetailResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI access is required to view chat conversations (no model in the org grants USE_AI to the caller).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Conversation not found. User-scoped keys also get 404 (not 403) when the conversation exists but belongs to a different user — existence of another user's conversations is not disclosed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/credit-controls": { + "get": { + "description": "Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per-user credit limit, plus read-only context (the credit limit, usage so far this billing period, and the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same AI-admin permission.", + "operationId": "aiCreditControlsGet", + "summary": "Get AI credit controls", + "tags": [ + "AI" + ], + "responses": { + "200": { + "description": "Current credit controls. Thresholds are `null` when the corresponding control is off.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditControlsResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions, or AI credit controls are not enabled for the organization. Requires AI-admin access.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + }, + "patch": { + "description": "Update the organization's AI credit controls: the downgrade and shutoff thresholds and the default per-user credit limit (userDefaultCredits). All fields are optional and tri-state: omit a field to leave it unchanged, send `null` to turn that control off (for userDefaultCredits: unlimited by default), or send a non-negative number to set it. At least one field is required. The `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the full current state, the same shape as GET.", + "operationId": "aiCreditControlsUpdate", + "summary": "Update AI credit controls", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditControlsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Thresholds updated. Returns the full current state.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditControlsResponse" + } + } + } + }, + "400": { + "description": "Invalid request. Common causes: empty body, a negative value, an unknown field, or downgradeCredits above shutoffCredits.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions, or AI credit controls are not enabled. Requires AI-admin access.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + } + }, + "/api/v1/ai/credit-controls/users": { + "get": { + "description": "List the organization's active individual user AI credit limits, ordered by userId ascending. Only users with an individual limit appear — everyone else follows the org default. A `null` creditLimit is an explicit unlimited override, distinct from following the default. Paginated via opaque cursors: pass `pageInfo.nextCursor` from one response as the `cursor` query parameter on the next request. Requires the same manage-user-attributes permission as the PATCH.", + "operationId": "aiCreditControlsUsersList", + "summary": "List individual users' AI credit limits", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + } + ], + "responses": { + "200": { + "description": "One page of users' individual AI credit limits.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditControlsUsersListResponse" + } + } + } + }, + "400": { + "description": "Invalid cursor or pageSize.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions, or per-user AI credit limits are not enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + }, + "patch": { + "description": "Set individual users' AI credit limits in bulk. Each entry names a user (`userId`) and either sets an individual limit (`creditLimit`: a non-negative number, or `null` for unlimited) or removes one (`useDefaultLimit: true`) so the user follows the org default. Each userId may appear at most once and must be a member of the organization. All updates are applied in one transaction, so either every entry takes effect or none do — an invalid userId fails the whole request with a 404 naming it. Requires the same manage-user-attributes permission as the AI credit limit settings pages.", + "operationId": "aiCreditControlsUsersUpdate", + "summary": "Set individual users' AI credit limits", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiUserCreditLimitsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "All entries applied. Returns each user's effective limit, in request order.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiUserCreditLimitsResponse" + } + } + } + }, + "400": { + "description": "Invalid request. Common causes: an empty users array, more than 1000 entries, an entry with both creditLimit and useDefaultLimit (or neither), a negative creditLimit, or a duplicated userId.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions, per-user AI credit limits are not enabled, or credit controls editing is disabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "A userId is not a member of the organization; the response names the first invalid id. No limits are changed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/routines": { + "get": { + "description": "List routines for the calling user, newest first. Includes routines paused by the owner or disabled by Omni, but excludes deleted routines. Use `pageInfo.nextCursor` from one response as the `cursor` query parameter on the next request. Organization API keys can pass `?userId=` to list routines for a specific organization member.", + "operationId": "routinesList", + "summary": "List routines", + "tags": [ + "AI Routines" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Field to sort results by" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of routines.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutinesListResponse" + } + } + } + }, + "400": { + "description": "Invalid pagination cursor or `userId` value.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to list routines for another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The `userId` membership was not found in the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + }, + "post": { + "description": "Create a routine that runs a saved prompt on a schedule and delivers the AI response through a single destination — email (one or more recipients / user groups) or Slack (a single channel or direct message). Each scheduled run executes once using the routine owner's permissions, and every recipient receives the same result. Organization API keys can pass `?userId=` to create the routine for a specific organization member.", + "operationId": "routineCreate", + "summary": "Create a routine", + "tags": [ + "AI Routines" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Routine created successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body, recipient configuration, schedule, or timezone. Also returned when the schedule is more frequent than the organization allows.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI routines or AI query generation are not enabled for the organization, or the API key cannot act on behalf of the requested user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Model, branch, or topic not found, or not accessible to the requested user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "429": { + "description": "The resolved user already has the maximum number of active routines.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError429" + } + } + } + } + } + } + }, + "/api/v1/ai/routines/{id}": { + "get": { + "description": "Get a single routine, including the status of its most recent completed run.", + "operationId": "routineGet", + "summary": "Get a routine", + "tags": [ + "AI Routines" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the routine." + }, + "required": true, + "description": "The UUID of the routine.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Routine details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineResponse" + } + } + } + }, + "400": { + "description": "Invalid routine ID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to access another user's routine.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Routine not found or has been deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + }, + "patch": { + "description": "Update a routine. All request fields are optional, and only supplied fields are changed. Supplying `destination` replaces the full recipient configuration.", + "operationId": "routineUpdate", + "summary": "Update a routine", + "tags": [ + "AI Routines" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the routine." + }, + "required": true, + "description": "The UUID of the routine.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Updated routine details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineResponse" + } + } + } + }, + "400": { + "description": "Invalid routine ID, request body, recipient configuration, schedule, or timezone.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to update another user's routine.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Routine not found or has been deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + }, + "delete": { + "description": "Delete a routine. It stops running immediately and no longer appears in list or get responses.", + "operationId": "routineDelete", + "summary": "Delete a routine", + "tags": [ + "AI Routines" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the routine." + }, + "required": true, + "description": "The UUID of the routine.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Routine deleted successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineDeleteResponse" + } + } + } + }, + "400": { + "description": "Invalid routine ID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to delete another user's routine.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Routine not found or has already been deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/routines/{id}/trigger": { + "post": { + "description": "Run a routine immediately, in addition to its schedule. The run executes once using the routine owner's permissions and delivers the AI response to every configured recipient — it is not a private preview. Returns once the run has started; the result is delivered asynchronously. Organization API keys can pass `?userId=` to act on behalf of a specific organization member.", + "operationId": "routineTrigger", + "summary": "Run a routine now", + "tags": [ + "AI Routines" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the routine." + }, + "required": true, + "description": "The UUID of the routine.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "202": { + "description": "The run has started.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineTriggerResponse" + } + } + } + }, + "400": { + "description": "Invalid routine ID, or the routine cannot run as configured (e.g. its model, branch, or owner is no longer accessible).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to run another user's routine.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The routine does not exist or cannot be triggered (deleted, paused, or disabled by Omni).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "409": { + "description": "A run is already in progress for this routine.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } + } + } + } + }, + "/api/v1/api-keys": { + "get": { + "description": "Returns all API tokens in the organization, including organization-level keys, personal access tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions.", + "operationId": "apiKeysList", + "summary": "List API tokens", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Cursor from the previous response (token UUID)" + }, + "required": false, + "description": "Cursor from the previous response (token UUID)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "createdAt", + "name" + ], + "default": "createdAt" + }, + "required": false, + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "organization", + "personal", + "mcp" + ], + "description": "Filter by API token type. When omitted, all types are returned.", + "example": "personal" + }, + "required": false, + "description": "Filter by API token type. When omitted, all types are returned.", + "name": "type", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of API tokens", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyListResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" + } + } + } + }, + "/api/v1/api-keys/{id}": { + "get": { + "description": "Returns a single API token by id. Requires organization admin permissions.", + "operationId": "apiKeysGet", + "summary": "Get API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The requested API token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKey" + } + } + } + }, + "400": { + "description": "Malformed `id` (must be a UUID)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Token not found in this organization" + } + } + }, + "put": { + "description": "Enables or disables an API token. Requires organization admin permissions.", + "operationId": "apiKeysUpdate", + "summary": "Enable or disable an API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "The updated API token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKey" + } + } + } + }, + "400": { + "description": "Invalid body, malformed `id`, or missing/malformed `Authorization` header" + }, + "403": { + "description": "Invalid bearer token, or caller lacks organization admin permissions" + }, + "404": { + "description": "Token not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + }, + "delete": { + "description": "Revokes an API token by permanently deleting it. Works for all token types. Requires organization admin permissions.", + "operationId": "apiKeysDelete", + "summary": "Revoke an API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The token was revoked", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyDeleteResponse" + } + } + } + }, + "400": { + "description": "Malformed `id`, or missing/malformed `Authorization` header" + }, + "403": { + "description": "Invalid bearer token, or caller lacks organization admin permissions" + }, + "404": { + "description": "Token not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + } + }, + "/api/v1/connections": { + "get": { + "operationId": "connectionsList", + "summary": "List connections", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Filter by database name (case-insensitive contains)", + "example": "analytics" + }, + "required": false, + "description": "Filter by database name (case-insensitive contains)", + "name": "database", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by dialect(s). Comma-separated list for multiple values", + "example": "snowflake,bigquery" + }, + "required": false, + "description": "Filter by dialect(s). Comma-separated list for multiple values", + "name": "dialect", + "in": "query" + }, + { + "schema": { + "type": "boolean", + "description": "Include soft-deleted connections in results", + "example": false + }, + "required": false, + "description": "Include soft-deleted connections in results", + "name": "includeDeleted", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by connection name (case-insensitive contains)", + "example": "Production" + }, + "required": false, + "description": "Filter by connection name (case-insensitive contains)", + "name": "name", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction", + "example": "desc" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "database", + "dialect", + "name" + ], + "description": "Field to sort by", + "example": "name" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of connections", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "allowBranchConnectionEnvironments": { + "type": [ + "boolean", + "null" + ], + "description": "Whether a branch may select its own connection environment. When user-attribute environment selection is also enabled, a branch selection overrides the user attribute.", + "example": false + }, + "baseRole": { + "type": [ + "string", + "null" + ], + "description": "Default role for users on this connection", + "example": "QUERIER" + }, + "branchConnectionEnvironmentOverridesUserAttr": { + "type": [ + "boolean", + "null" + ], + "deprecated": true, + "description": "Deprecated alias for `allowBranchConnectionEnvironments`; same value. Use `allowBranchConnectionEnvironments` instead.", + "example": false + }, + "createdAt": { + "type": "string", + "description": "Timestamp when connection was created (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "database": { + "type": [ + "string", + "null" + ], + "description": "Database name", + "example": "analytics_db" + }, + "defaultSchema": { + "type": [ + "string", + "null" + ], + "description": "Default schema for the connection", + "example": "public" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when connection was deleted (ISO 8601)", + "example": null + }, + "dialect": { + "type": "string", + "enum": [ + "snowflake", + "bigquery", + "redshift", + "postgres", + "mysql", + "mariadb", + "databricks", + "databricks_lakebase", + "trino", + "athena", + "duckdb", + "motherduck", + "sqlserver", + "clickhouse", + "singlestore" + ], + "description": "Database dialect type", + "example": "snowflake" + }, + "environmentConnectionSwitchesSchemaModel": { + "type": [ + "boolean", + "null" + ], + "description": "Whether environment connections switch schema model", + "example": false + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection identifier", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "name": { + "type": "string", + "description": "Connection display name", + "example": "Production Snowflake" + }, + "updatedAt": { + "type": "string", + "description": "Timestamp when connection was last updated (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "userAttributeNameForConnectionEnvironments": { + "type": [ + "string", + "null" + ], + "description": "User attribute name used for connection environments", + "example": "region" + }, + "userAttributeValuesForDefaultEnvironment": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default user attribute values for the base environment", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "allowBranchConnectionEnvironments", + "baseRole", + "branchConnectionEnvironmentOverridesUserAttr", + "createdAt", + "database", + "defaultSchema", + "deletedAt", + "dialect", + "environmentConnectionSwitchesSchemaModel", + "id", + "name", + "updatedAt", + "userAttributeNameForConnectionEnvironments", + "userAttributeValuesForDefaultEnvironment" + ], + "description": "Connection object", + "title": "Connection" + }, + "description": "List of connections" + } + }, + "required": [ + "connections" + ], + "description": "List connections response", + "title": "ConnectionsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + }, + "post": { + "description": "Create a new database connection. The request body varies by dialect - see dialect-specific documentation for required fields.", + "operationId": "connectionsCreate", + "summary": "Create connection", + "tags": [ + "Connections" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "acceptsLicense": { + "type": "boolean", + "description": "Acceptance of the license terms. Required for Oracle connections.", + "example": true + }, + "allowsUserSpecificTimezones": { + "type": "boolean", + "default": false, + "description": "Whether to allow users to specify their own timezones", + "example": false + }, + "alwaysScopeViewNames": { + "type": "boolean", + "description": "Whether to always include schema (and catalog) prefixes in generated view names, even for tables in the default schema. Defaults to true for dialects that support multiple catalogs, false otherwise.", + "example": true + }, + "authenticationType": { + "type": "string", + "description": "Authentication type. Applicable for BigQuery, MSSQL, Snowflake, Databricks, and Athena.", + "example": "snowflake-password" + }, + "awsRoleArn": { + "type": "string", + "description": "AWS IAM role ARN. Applicable for Athena only.", + "example": "arn:aws:iam::123456789012:role/OmniAthenaRole" + }, + "baseRole": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "RESTRICTED_QUERIER", + "QUERIER", + "MODELER", + "CONNECTION_ADMIN" + ], + "description": "The default role for users accessing the connection", + "example": "QUERIER" + }, + "database": { + "type": "string", + "description": "The default database/catalog to connect to. For BigQuery, this is the project ID. For Athena, this is the data catalog.", + "example": "analytics_db" + }, + "defaultSchema": { + "type": "string", + "description": "The default schema to use. Required for MSSQL.", + "example": "public" + }, + "dialect": { + "type": "string", + "enum": [ + "athena", + "bigquery", + "clickhouse", + "databricks", + "databricks_lakebase", + "exasol", + "mariadb", + "motherduck", + "mssql", + "mysql", + "oracle", + "postgres", + "redshift", + "sap_hana", + "snowflake", + "starrocks", + "trino" + ], + "description": "The database dialect", + "example": "snowflake" + }, + "enableDbSemanticLayerIntegration": { + "type": "boolean", + "default": false, + "description": "Enable the dialect-native semantic layer integration. Applicable for Snowflake and Databricks.", + "example": false + }, + "enableDbSemanticLayerTopics": { + "type": "boolean", + "default": false, + "description": "Enable the dialect-native semantic layer topics. Applicable for Snowflake and Databricks.", + "example": false + }, + "externalOauthAudience": { + "type": "string", + "description": "External OAuth audience claim. Applicable for Snowflake." + }, + "externalOauthAuthorizationUrl": { + "type": "string", + "format": "uri", + "description": "External OAuth authorization URL (must be HTTPS). Applicable for Snowflake.", + "example": "https://oauth.example.com/authorize" + }, + "externalOauthTokenUrl": { + "type": "string", + "format": "uri", + "description": "External OAuth token URL (must be HTTPS). Applicable for Snowflake.", + "example": "https://oauth.example.com/token" + }, + "host": { + "type": "string", + "description": "The hostname or IP address of the database server. For Snowflake, provide only the account identifier.", + "example": "myaccount" + }, + "hostOverride": { + "type": "string", + "description": "Custom Snowflake host (when not using the account identifier). Mutually exclusive with `host`.", + "example": "myaccount.snowflakecomputing.com" + }, + "includeOtherCatalogs": { + "type": "string", + "description": "Comma-separated list of other catalogs/databases to include. Only applicable for databases that support multi-catalog queries.", + "example": "other_project1,other_project2" + }, + "includeSchemas": { + "type": "string", + "description": "Comma-separated list of schemas to include. Leave empty to include all schemas.", + "example": "public,analytics" + }, + "inferRelationshipsFromColumnNames": { + "type": "boolean", + "default": true, + "description": "Whether to infer relationships from column-name conventions during schema refresh. Defaults to true.", + "example": true + }, + "inferRelationshipsFromForeignKeys": { + "type": "boolean", + "default": false, + "description": "Whether to infer relationships from declared foreign keys during schema refresh. Currently honored for Postgres and Snowflake.", + "example": false + }, + "maxBillingBytes": { + "type": "string", + "description": "Maximum bytes that can be billed for a BigQuery query. Applicable for BigQuery only.", + "example": "1000000000" + }, + "name": { + "type": "string", + "description": "A descriptive name for the connection", + "example": "Production Warehouse" + }, + "oauthClientId": { + "type": "string", + "description": "OAuth client ID for admin schema refresh. Applicable for Snowflake and Databricks." + }, + "oauthClientSecretUnencrypted": { + "type": "string", + "description": "OAuth client secret for admin schema refresh. Applicable for Snowflake and Databricks." + }, + "offloadedSchemas": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Schemas whose tables should be queried via the offloaded engine. Accepts a comma-separated string or an array of schema names.", + "example": [ + "analytics_archive" + ] + }, + "passwordUnencrypted": { + "type": "string", + "description": "The password to authenticate with. For BigQuery, this must be the JSON service account key file content. For Snowflake with keypair authentication, this can be omitted." + }, + "port": { + "type": "integer", + "description": "The port number for the database connection. Not required for Snowflake, MotherDuck, BigQuery, Databricks, and Athena.", + "example": 5432 + }, + "privateKey": { + "type": "string", + "description": "An RSA key for keypair authentication. Omni will automatically add PEM headers if none are provided. Applicable for Snowflake only." + }, + "queryTimeoutSeconds": { + "type": "integer", + "maximum": 3600, + "description": "The timeout in seconds for queries. Maximum value is 3600 (1 hour). Only applicable for databases that support query timeouts.", + "example": 900 + }, + "queryTimezone": { + "type": "string", + "description": "The timezone to use for queries", + "example": "NONE" + }, + "region": { + "type": "string", + "description": "Required for BigQuery and Athena connections. For BigQuery, specify a region like \"us\". For Athena, specify an AWS region like \"us-east-1\".", + "example": "us-east-1" + }, + "scratchSchema": { + "type": "string", + "description": "Schema to use for data input (upload) tables. If not specified, a suitable default will be chosen.", + "example": "omni_scratch" + }, + "systemTimezone": { + "type": "string", + "description": "The timezone to use for the system", + "example": "UTC" + }, + "trustServerCertificate": { + "type": "boolean", + "default": false, + "description": "Whether to trust the server certificate. Applicable for MSSQL, Exasol, ClickHouse, Trino, and SAP HANA.", + "example": false + }, + "useMachineAuth": { + "type": "boolean", + "description": "Whether to authenticate using machine credentials (OAuth M2M). Applicable for Athena and Databricks.", + "example": false + }, + "username": { + "type": "string", + "description": "The username to authenticate with. For BigQuery, this is the client email from the service account.", + "example": "analytics_user" + }, + "warehouse": { + "type": "string", + "description": "Required for Snowflake (specify the warehouse) and Databricks (specify the HTTP path). May be omitted for Snowflake OAuth connections, in which case each user's Snowflake default warehouse applies.", + "example": "COMPUTE_WH" + }, + "wifAudience": { + "type": "string", + "description": "Full resource name of the workload identity pool provider. Required for BigQuery workload identity federation authentication.", + "example": "//iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider" + }, + "wifServiceAccountEmail": { + "type": "string", + "description": "Service account to impersonate for BigQuery workload identity federation authentication. When omitted, the federated identity is used directly.", + "example": "omni@my-project.iam.gserviceaccount.com" + } + }, + "required": [ + "dialect", + "name", + "passwordUnencrypted" + ], + "description": "Request body for creating a database connection. Required fields: dialect, name, passwordUnencrypted. Additional fields may be required depending on the dialect.", + "title": "ConnectionsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Connection created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "string", + "format": "uuid", + "description": "Created connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "data", + "success" + ], + "description": "Create connection response", + "title": "ConnectionsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or dialect" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + } + }, + "/api/v1/connections/{id}": { + "get": { + "description": "Fetch a single connection by ID.", + "operationId": "connectionsGet", + "summary": "Get connection", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Connection object", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connection": { + "type": "object", + "properties": { + "allowBranchConnectionEnvironments": { + "type": [ + "boolean", + "null" + ], + "description": "Whether a branch may select its own connection environment. When user-attribute environment selection is also enabled, a branch selection overrides the user attribute.", + "example": false + }, + "baseRole": { + "type": [ + "string", + "null" + ], + "description": "Default role for users on this connection", + "example": "QUERIER" + }, + "branchConnectionEnvironmentOverridesUserAttr": { + "type": [ + "boolean", + "null" + ], + "deprecated": true, + "description": "Deprecated alias for `allowBranchConnectionEnvironments`; same value. Use `allowBranchConnectionEnvironments` instead.", + "example": false + }, + "createdAt": { + "type": "string", + "description": "Timestamp when connection was created (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "database": { + "type": [ + "string", + "null" + ], + "description": "Database name", + "example": "analytics_db" + }, + "defaultSchema": { + "type": [ + "string", + "null" + ], + "description": "Default schema for the connection", + "example": "public" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when connection was deleted (ISO 8601)", + "example": null + }, + "dialect": { + "type": "string", + "enum": [ + "snowflake", + "bigquery", + "redshift", + "postgres", + "mysql", + "mariadb", + "databricks", + "databricks_lakebase", + "trino", + "athena", + "duckdb", + "motherduck", + "sqlserver", + "clickhouse", + "singlestore" + ], + "description": "Database dialect type", + "example": "snowflake" + }, + "environmentConnectionSwitchesSchemaModel": { + "type": [ + "boolean", + "null" + ], + "description": "Whether environment connections switch schema model", + "example": false + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection identifier", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "name": { + "type": "string", + "description": "Connection display name", + "example": "Production Snowflake" + }, + "updatedAt": { + "type": "string", + "description": "Timestamp when connection was last updated (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "userAttributeNameForConnectionEnvironments": { + "type": [ + "string", + "null" + ], + "description": "User attribute name used for connection environments", + "example": "region" + }, + "userAttributeValuesForDefaultEnvironment": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default user attribute values for the base environment", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "allowBranchConnectionEnvironments", + "baseRole", + "branchConnectionEnvironmentOverridesUserAttr", + "createdAt", + "database", + "defaultSchema", + "deletedAt", + "dialect", + "environmentConnectionSwitchesSchemaModel", + "id", + "name", + "updatedAt", + "userAttributeNameForConnectionEnvironments", + "userAttributeValuesForDefaultEnvironment" + ], + "description": "Connection object", + "title": "Connection" + } + }, + "required": [ + "connection" + ], + "description": "Get connection response", + "title": "ConnectionsGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied — caller lacks READ on the connection" + }, + "404": { + "description": "Connection does not exist" + } + } + }, + "patch": { + "description": "Update connection settings including base role, environment user attributes, and credentials.\n\nCredential fields:\n- `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery)\n- `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication\n\nNote: Credentials are encrypted at rest and never returned in API responses.", + "operationId": "connectionsUpdate", + "summary": "Update connection", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "Default role to assign to this connection", + "example": "QUERIER" + }, + "environmentUserAttribute": { + "type": [ + "object", + "null" + ], + "properties": { + "attributeName": { + "type": "string", + "description": "Name of the user attribute for environment selection", + "example": "region" + }, + "defaultValues": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default values for the user attribute", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "attributeName", + "defaultValues" + ], + "description": "User attribute settings for connection environments" + }, + "passwordUnencrypted": { + "type": "string", + "description": "New password or service account key. For BigQuery, this must be the JSON service account key file content." + }, + "privateKey": { + "type": "string", + "description": "RSA private key for keypair authentication (Snowflake only). Must be PEM-encoded PKCS#8 format, minimum 2048-bit." + } + }, + "description": "Request body for updating connection attributes and credentials. At least one field must be provided.", + "title": "ConnectionsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Connection updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Status message describing what was updated", + "example": "Updated connection default role." + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "Update connection response", + "title": "ConnectionsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - at least one field must be provided" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "delete": { + "description": "Archive a connection (move to trash). Archived connections can be restored from the trash in the connection settings UI.\n\nA connection that is already archived returns 410.", + "operationId": "connectionsDelete", + "summary": "Delete connection", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Connection moved to trash", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Status message describing the result", + "example": "Connection moved to trash." + }, + "success": { + "type": "boolean", + "description": "True when the connection was archived", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "Archive connection response", + "title": "ConnectionsDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + }, + "410": { + "description": "Connection has already been archived" + } + } + } + }, + "/api/v1/connections/{connectionId}/dbt": { + "get": { + "operationId": "connectionsDbtGet", + "summary": "Get dbt configuration", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "dbt configuration for the connection", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "type": "object", + "properties": { + "autogenRelationships": { + "type": "boolean", + "description": "Whether relationships are auto-generated from dbt", + "example": true + }, + "branch": { + "type": "string", + "description": "Git branch name", + "example": "main" + }, + "dbtVersion": { + "type": "string", + "description": "dbt version being used", + "example": "Auto" + }, + "enableSemanticLayer": { + "type": "boolean", + "description": "Whether the dbt semantic layer integration is enabled", + "example": false + }, + "enableVirtualSchemas": { + "type": "boolean", + "description": "Whether virtual schemas are enabled", + "example": false + }, + "projectRootPath": { + "type": [ + "string", + "null" + ], + "description": "Path to dbt project root", + "example": "dbt_project" + }, + "sshUrl": { + "type": "string", + "description": "SSH URL for git repository", + "example": "git@github.com:org/repo.git" + }, + "supportsDbt": { + "type": "boolean", + "enum": [ + true + ], + "description": "Indicates dbt is supported and configured", + "example": true + } + }, + "required": [ + "autogenRelationships", + "branch", + "dbtVersion", + "enableSemanticLayer", + "enableVirtualSchemas", + "projectRootPath", + "sshUrl", + "supportsDbt" + ], + "description": "dbt repository configuration response", + "title": "DbtConfiguredResponse" + }, + { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Message explaining dbt status", + "example": "dbt not configured for this connection" + }, + "supportsDbt": { + "type": "boolean", + "description": "Whether the connection dialect supports dbt", + "example": true + } + }, + "required": [ + "message", + "supportsDbt" + ], + "description": "Response when dbt is not configured", + "title": "DbtNotConfiguredResponse" + } + ], + "description": "dbt configuration response", + "title": "ConnectionsDbtGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "put": { + "operationId": "connectionsDbtUpdate", + "summary": "Update dbt configuration", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "autogenRelationships": { + "type": "boolean", + "description": "Automatically generate relationships from dbt", + "example": true + }, + "branch": { + "type": "string", + "minLength": 1, + "description": "Git branch name", + "example": "main" + }, + "dbtVersion": { + "type": [ + "string", + "null" + ], + "description": "dbt version to use. Supported: Auto, 1.11, 1.12", + "example": "1.11" + }, + "enableSemanticLayer": { + "type": "boolean", + "default": false, + "description": "Enable dbt semantic layer integration", + "example": false + }, + "enableVirtualSchemas": { + "type": "boolean", + "description": "Enable virtual schemas from dbt", + "example": false + }, + "projectRootPath": { + "anyOf": [ + { + "type": "string", + "pattern": "^(?!\\/)(?!.*\\.\\.)[\\w ./-]+$" + }, + { + "type": "string", + "enum": [ + "" + ] + }, + { + "type": [ + "object", + "null" + ], + "enum": [ + null + ] + }, + { + "type": "null" + } + ], + "default": null, + "description": "Path to dbt project root within repository", + "example": "dbt_project" + }, + "rotateKeys": { + "type": "boolean", + "default": false, + "description": "Rotate SSH deploy keys", + "example": false + }, + "sshUrl": { + "type": "string", + "minLength": 1, + "description": "SSH URL for git repository", + "example": "git@github.com:org/repo.git" + } + }, + "required": [ + "autogenRelationships", + "branch", + "enableVirtualSchemas", + "sshUrl" + ], + "description": "dbt repository configuration", + "title": "ConnectionsDbtUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "dbt configuration updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "dbt configuration updated successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "dbt update response", + "title": "ConnectionsDbtUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or validation error" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "delete": { + "operationId": "connectionsDbtDelete", + "summary": "Delete dbt configuration", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "dbt configuration deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "dbt repository unlinked successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "dbt delete response", + "title": "ConnectionsDbtDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found or dbt not configured" + } + } + } + }, + "/api/v1/connections/{connectionId}/dbt/environments": { + "get": { + "description": "List all dbt environments for a connection.", + "operationId": "connectionsDbtEnvironmentsList", + "summary": "List dbt environments", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name" + ], + "default": "name", + "description": "Field to sort results by", + "example": "name" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of dbt environments", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection not found" + } + } + }, + "post": { + "description": "Create a new dbt environment for a connection.", + "operationId": "connectionsDbtEnvironmentsCreate", + "summary": "Create dbt environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "dbt environment created successfully", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentItem" + }, + { + "description": "Created dbt environment", + "title": "DbtEnvironmentCreateResponse" + } + ] + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection not found" + } + } + } + }, + "/api/v1/connections/{connectionId}/dbt/environments/{environmentId}": { + "put": { + "description": "Update an existing dbt environment for a connection.", + "operationId": "connectionsDbtEnvironmentsUpdate", + "summary": "Update dbt environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Environment ID", + "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + }, + "required": true, + "description": "Environment ID", + "name": "environmentId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "dbt environment updated successfully", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentItem" + }, + { + "description": "Updated dbt environment", + "title": "DbtEnvironmentUpdateResponse" + } + ] + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection or environment not found" + } + } + }, + "delete": { + "description": "Delete a dbt environment from a connection.", + "operationId": "connectionsDbtEnvironmentsDelete", + "summary": "Delete dbt environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Environment ID", + "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + }, + "required": true, + "description": "Environment ID", + "name": "environmentId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "dbt environment deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection or environment not found" + } + } + } + }, + "/api/v1/connections/{connectionId}/schedules": { + "get": { + "operationId": "connectionsSchedulesList", + "summary": "List schema refresh schedules", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "List of schema refresh schedules", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "schedules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Schema refresh schedule object", + "title": "ConnectionSchedule" + }, + "description": "List of schema refresh schedules" + } + }, + "required": [ + "schedules" + ], + "description": "List schedules response", + "title": "ConnectionsSchedulesListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "post": { + "operationId": "connectionsSchedulesCreate", + "summary": "Create schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hardRefresh": { + "type": "boolean", + "default": false, + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + } + }, + "required": [ + "schedule", + "timezone" + ], + "description": "Request body for creating a schema refresh schedule", + "title": "ConnectionsSchedulesCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Schema refresh schedule created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Created schedule response", + "title": "ConnectionsSchedulesCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid cron expression or timezone" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + } + }, + "/api/v1/connections/{connectionId}/schedules/{scheduleId}": { + "get": { + "operationId": "connectionsSchedulesGet", + "summary": "Get schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schema refresh schedule details", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Get schedule response", + "title": "ConnectionsSchedulesGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection or schedule not found" + } + } + }, + "put": { + "operationId": "connectionsSchedulesUpdate", + "summary": "Update schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hardRefresh": { + "type": "boolean", + "default": false, + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + } + }, + "required": [ + "schedule", + "timezone" + ], + "description": "Request body for updating a schema refresh schedule", + "title": "ConnectionsSchedulesUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Schema refresh schedule updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Updated schedule response", + "title": "ConnectionsSchedulesUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid cron expression or timezone" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection or schedule not found" + } + } + }, + "delete": { + "operationId": "connectionsSchedulesDelete", + "summary": "Delete schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schema refresh schedule deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "success" + ], + "description": "Delete schedule response", + "title": "ConnectionsSchedulesDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection or schedule not found" + } + } + } + }, + "/api/v1/connection-environments": { + "post": { + "operationId": "connectionEnvironmentsCreate", + "summary": "Create connection environments", + "tags": [ + "Connections" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "environmentConnectionIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "IDs of connections to use as environments", + "example": [ + "550e8400-e29b-41d4-a716-446655440002", + "550e8400-e29b-41d4-a716-446655440003" + ] + } + }, + "required": [ + "baseConnectionId", + "environmentConnectionIds" + ], + "description": "Request body for creating connection environments", + "title": "ConnectionsEnvironmentsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Connection environments created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionEnvironments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the environment connection", + "example": "550e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection environment identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } + }, + "required": [ + "baseConnectionId", + "connectionId", + "id", + "userAttributeValues" + ], + "description": "Connection environment object", + "title": "ConnectionEnvironment" + }, + "description": "Created connection environments" + } + }, + "required": [ + "connectionEnvironments" + ], + "description": "Create connection environments response", + "title": "ConnectionsEnvironmentsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or connection IDs" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "Base connection or environment connection not found" + } + } + } + }, + "/api/v1/connection-environments/{id}": { + "put": { + "operationId": "connectionEnvironmentsUpdate", + "summary": "Update connection environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection environment ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Connection environment ID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } + }, + "required": [ + "userAttributeValues" + ], + "description": "Request body for updating a connection environment", + "title": "ConnectionsEnvironmentsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Connection environment updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "success" + ], + "description": "Update connection environment response", + "title": "ConnectionsEnvironmentsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "Connection environment not found" + } + } + }, + "delete": { + "operationId": "connectionEnvironmentsDelete", + "summary": "Delete connection environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection environment ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Connection environment ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Connection environment deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "success" + ], + "description": "Delete connection environment response", + "title": "ConnectionsEnvironmentsDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "Connection environment not found" + } + } + } + }, + "/api/v1/content": { + "get": { + "operationId": "contentList", + "summary": "List content", + "tags": [ + "Content" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by creator user ID" + }, + "required": false, + "description": "Filter by creator user ID", + "name": "creatorId", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by folder ID (cannot be used with path)" + }, + "required": false, + "description": "Filter by folder ID (cannot be used with path)", + "name": "folderId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of fields to include (e.g., _count,labels)" + }, + "required": false, + "description": "Comma-separated list of fields to include (e.g., _count,labels)", + "name": "include", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by folder path (cannot be used with folderId)", + "example": "/reports/sales" + }, + "required": false, + "description": "Filter by folder path (cannot be used with folderId)", + "name": "path", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Filter by share scope", + "example": "organization" + }, + "required": false, + "description": "Filter by share scope", + "name": "scope", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction", + "example": "asc" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name", + "favorites" + ], + "description": "Field to sort by", + "example": "name" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of content (documents and folders)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentListResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters (cannot use both folderId and path)" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Folder not found (when filtering by path)" + } + } + } + }, + "/api/v1/dashboards/{identifier}/download": { + "post": { + "operationId": "dashboardsDownload", + "summary": "Initiate dashboard download", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardsDownloadBody" + } + } + } + }, + "responses": { + "200": { + "description": "Download job initiated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardsDownloadResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or filter configuration" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - cannot download this dashboard" + }, + "404": { + "description": "Dashboard not found" + }, + "409": { + "description": "Download already in progress for this dashboard" + }, + "500": { + "description": "Failed to initiate download" + } + } + } + }, + "/api/v1/dashboards/{identifier}/download/{jobId}": { + "get": { + "operationId": "dashboardsDownloadFile", + "summary": "Get download file", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Download job ID (UUID)", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Download job ID (UUID)", + "name": "jobId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "File ready - binary content streamed" + }, + "202": { + "description": "Download job still in progress" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Dashboard or download job not found" + }, + "410": { + "description": "Download job failed" + }, + "500": { + "description": "Failed to retrieve download artifact" + } + } + } + }, + "/api/v1/dashboards/{identifier}/download/{jobId}/status": { + "get": { + "operationId": "dashboardsDownloadStatus", + "summary": "Get download job status", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Download job ID (UUID)", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Download job ID (UUID)", + "name": "jobId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Download job status" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Dashboard or download job not found" + } + } + } + }, + "/api/v1/dashboards/{identifier}/filters": { + "get": { + "operationId": "dashboardsGetFilters", + "summary": "Get dashboard filters", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Dashboard filter and control configuration", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardFiltersResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - VIEWER role required" + }, + "404": { + "description": "Dashboard not found" + } + } + }, + "patch": { + "operationId": "dashboardsUpdateFilters", + "summary": "Update dashboard filters", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardsUpdateFiltersBody" + } + } + } + }, + "responses": { + "200": { + "description": "Filters updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardFiltersResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - must include at least one filter, control, or filterOrder" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - EDITOR role required" + }, + "404": { + "description": "Dashboard not found or document does not have a dashboard" + }, + "409": { + "description": "Conflict - draft already exists. Set clearExistingDraft to true to proceed." + } + } + } + }, + "/api/v1/documents": { + "get": { + "operationId": "documentsList", + "summary": "List documents", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by creator membership ID" + }, + "required": false, + "description": "Filter by creator membership ID", + "name": "creatorId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination" + }, + "required": false, + "description": "Cursor for pagination", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by folder ID" + }, + "required": false, + "description": "Filter by folder ID", + "name": "folderId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", + "example": "_count,labels" + }, + "required": false, + "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", + "name": "include", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of label names to filter by", + "example": "verified,important" + }, + "required": false, + "description": "Comma-separated list of label names to filter by", + "name": "labels", + "in": "query" + }, + { + "schema": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 50, + "description": "Number of records per page" + }, + "required": false, + "description": "Number of records per page", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name", + "favorites", + "updatedAt", + "visits" + ], + "default": "name", + "description": "Field to sort by" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter documents visible to this membership ID" + }, + "required": false, + "description": "Filter documents visible to this membership ID", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of documents", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + } + } + }, + "post": { + "operationId": "documentsCreate", + "summary": "Create document", + "tags": [ + "Documents" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Document created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or branch not found" + } + } + } + }, + "/api/v1/documents/{identifier}": { + "get": { + "description": "Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a document, modify the response, and PUT it back to update. Only dashboard documents are supported; analysis documents return 400.", + "operationId": "documentsGet", + "summary": "Get document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Document details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetResponse" + } + } + } + }, + "400": { + "description": "Analysis documents are not supported" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions to view the document" + }, + "404": { + "description": "Document not found" + } + } + }, + "put": { + "deprecated": true, + "description": "**Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). Scheduled for removal on July 31, 2026 (see the `Sunset` response header).\n\nUpdates a document with the specified identifier. This endpoint performs a full resource replacement — all required fields must be provided and existing query presentations are replaced entirely. Only dashboard documents are supported; analysis documents and documents without an associated dashboard return 400. For published documents, the update goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", + "operationId": "documentsPut", + "summary": "Replace document (full replacement)", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsPutBody" + } + } + } + }, + "responses": { + "200": { + "description": "Document replaced successfully", + "headers": { + "Deprecation": { + "schema": { + "type": "string", + "enum": [ + "true" + ], + "description": "Marks the endpoint as deprecated." + }, + "required": true, + "description": "Marks the endpoint as deprecated." + }, + "Link": { + "schema": { + "type": "string", + "description": "Points to the v2 successor resource.", + "example": "; rel=\"successor-version\"" + }, + "required": true, + "description": "Points to the v2 successor resource." + }, + "Sunset": { + "schema": { + "type": "string", + "description": "Date the endpoint will be removed, in RFC 1123 form (RFC 8594).", + "example": "Fri, 31 Jul 2026 00:00:00 GMT" + }, + "required": true, + "description": "Date the endpoint will be removed, in RFC 1123 form (RFC 8594)." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsPutResponse" + } + } + } + }, + "400": { + "description": "Invalid request body, missing required fields, or validation error (also returned for analysis documents and documents without an associated dashboard)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions to update the document" + }, + "404": { + "description": "Document not found" + }, + "409": { + "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" + } + } + }, + "patch": { + "deprecated": true, + "description": "**Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). Scheduled for removal on July 31, 2026 (see the `Sunset` response header).\n\nUpdates a document's name, description, and/or identifier. This is a partial update — only provided fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. When `identifier` is changed, the previous identifier is retained in the document identifier history and continues to redirect. For published documents, the update goes through a draft/publish workflow automatically.", + "operationId": "documentsUpdate", + "summary": "Rename document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Document updated successfully", + "headers": { + "Deprecation": { + "schema": { + "type": "string", + "enum": [ + "true" + ], + "description": "Marks the endpoint as deprecated." + }, + "required": true, + "description": "Marks the endpoint as deprecated." + }, + "Link": { + "schema": { + "type": "string", + "description": "Points to the v2 successor resource.", + "example": "; rel=\"successor-version\"" + }, + "required": true, + "description": "Points to the v2 successor resource." + }, + "Sunset": { + "schema": { + "type": "string", + "description": "Date the endpoint will be removed, in RFC 1123 form (RFC 8594).", + "example": "Fri, 31 Jul 2026 00:00:00 GMT" + }, + "required": true, + "description": "Date the endpoint will be removed, in RFC 1123 form (RFC 8594)." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or validation error (e.g. missing name/description/identifier, name too long, identifier already in use)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - EDITOR role required" + }, + "404": { + "description": "Document not found" + }, + "409": { + "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" + } + } + }, + "delete": { + "operationId": "documentsDelete", + "summary": "Delete document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Document deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/queries": { + "get": { + "operationId": "documentsGetQueries", + "summary": "List document queries", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "List of queries in the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetQueriesResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/move": { + "put": { + "operationId": "documentsMove", + "summary": "Move document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsMoveBody" + } + } + } + }, + "responses": { + "200": { + "description": "Document moved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid folder path or scope" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document or folder not found" + } + } + } + }, + "/api/v1/documents/{identifier}/permissions": { + "get": { + "operationId": "documentsGetPermissions", + "summary": "Get document permissions", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "User membership ID to check permissions for" + }, + "required": true, + "description": "User membership ID to check permissions for", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "User permissions for the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetPermissionsResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document or user not found" + } + } + }, + "put": { + "operationId": "documentsUpdatePermissionSettings", + "summary": "Update document permission settings", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdatePermissionSettingsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permission settings updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document not found" + } + } + }, + "post": { + "operationId": "documentsAddPermits", + "summary": "Add document permits", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsAddPermitsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permissions added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document not found" + } + } + }, + "patch": { + "operationId": "documentsUpdatePermits", + "summary": "Update document permits", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdatePermitsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permissions updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document not found" + } + } + }, + "delete": { + "operationId": "documentsRevokePermits", + "summary": "Revoke document permits", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsRevokePermitsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permissions revoked successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/draft": { + "post": { + "operationId": "documentsCreateDraft", + "summary": "Create document draft", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateDraftBody" + } + } + } + }, + "responses": { + "200": { + "description": "Draft created or existing draft returned", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateDraftResponse" + } + } + } + }, + "400": { + "description": "Document is not eligible for publishing workflow" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - EDITOR role required" + }, + "404": { + "description": "Document or branch not found" + } + } + }, + "delete": { + "operationId": "documentsDiscardDraft", + "summary": "Discard document draft", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsDiscardDraftBody" + } + } + } + }, + "responses": { + "200": { + "description": "Draft discarded successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsDiscardDraftResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document or draft not found" + } + } + } + }, + "/api/v1/documents/{identifier}/drafts": { + "get": { + "description": "Lists drafts for a document with branch context. By default only active drafts are returned; pass `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by `createdAt` descending.", + "operationId": "documentsListDrafts", + "summary": "List document drafts", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", + "example": "archived" + }, + "required": false, + "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", + "name": "include", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of drafts for the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsListDraftsResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions to view the document" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/duplicate": { + "post": { + "operationId": "documentsDuplicate", + "summary": "Duplicate document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsDuplicateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Document duplicated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsDuplicateResponse" + } + } + } + }, + "400": { + "description": "Invalid name or folder path" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document or folder not found" + } + } + } + }, + "/api/v1/documents/{identifier}/upgrade": { + "post": { + "description": "Upgrades a document to the advanced dashboard layout (the \"File > Upgrade layout\" UI action). No-ops when the document already has advanced layout. For published documents the upgrade goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", + "operationId": "documentsUpgradeLayout", + "summary": "Upgrade dashboard layout", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpgradeLayoutBody" + } + } + } + }, + "responses": { + "200": { + "description": "Layout upgraded, or no-op if the document already had advanced layout", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpgradeLayoutResponse" + } + } + } + }, + "400": { + "description": "Document does not have a dashboard to upgrade" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + }, + "409": { + "description": "A draft already exists for the published document; set clearExistingDraft to override" + } + } + } + }, + "/api/v1/documents/{identifier}/favorite": { + "put": { + "operationId": "documentsAddFavorite", + "summary": "Add document to favorites", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Favorite added successfully" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + } + } + }, + "delete": { + "operationId": "documentsRemoveFavorite", + "summary": "Remove document from favorites", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Favorite removed successfully" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/labels": { + "patch": { + "operationId": "documentsBulkUpdateLabels", + "summary": "Bulk update document labels", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Labels updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsResponse" + } + } + } + }, + "400": { + "description": "Invalid request - at least one label must be specified" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/labels/{labelName}": { + "put": { + "operationId": "documentsAddLabel", + "summary": "Add label to document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier", + "example": "abc123" + }, + "required": true, + "description": "Document identifier", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "labelName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Label added successfully" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document or label not found" + } + } + }, + "delete": { + "operationId": "documentsRemoveLabel", + "summary": "Remove label from document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier", + "example": "abc123" + }, + "required": true, + "description": "Document identifier", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "labelName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Label removed successfully" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/transfer-ownership": { + "put": { + "operationId": "documentsTransferOwnership", + "summary": "Transfer document ownership", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsTransferOwnershipBody" + } + } + } + }, + "responses": { + "200": { + "description": "Ownership transferred successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid user ID" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role or owner required" + }, + "404": { + "description": "Document or user not found" + } + } + } + }, + "/api/v1/documents/{identifier}/access-list": { + "get": { + "operationId": "documentsAccessList", + "summary": "List document access principals", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction (default: asc)", + "example": "desc" + }, + "required": false, + "description": "Sort direction (default: asc)", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Field to sort results by" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "direct", + "folder" + ], + "description": "Filter by access source: direct or folder" + }, + "required": false, + "description": "Filter by access source: direct or folder", + "name": "accessSource", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "user", + "userGroup" + ], + "description": "Filter by principal type: user or userGroup" + }, + "required": false, + "description": "Filter by principal type: user or userGroup", + "name": "type", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of users and groups with access", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsAccessListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - VIEWER role required" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/favorites": { + "get": { + "description": "Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need to preserve favorites when replacing documents, without iterating every user in the organization.", + "operationId": "documentsListFavorites", + "summary": "List users who favorited the document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction by favoritedAt (default: asc — oldest first)", + "example": "desc" + }, + "required": false, + "description": "Sort direction by favoritedAt (default: asc — oldest first)", + "name": "sortDirection", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of users who favorited the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsListFavoritesResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied — caller lacks MANAGER on the document, or used a user-scoped (personal access token) API key (org-scoped only)" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v2/documents": { + "post": { + "description": "Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body — `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed.\n\nWhen `containers` is omitted, every dashboard-eligible tile is auto-placed in a default layout. When `containers` is present, it fully defines the layout — tiles it does not reference are stored but not rendered. Send `containers: null` to create a workbook-only document with no dashboard (`controls` and `settings` must then be omitted); an empty `containers: []` is rejected.\n\nThe new document is published live before the response returns. As a first publish of brand-new content it is not subject to the org’s `requirePullRequestToPublish` policy (which gates edits to existing content).", + "operationId": "documentsV2Create", + "summary": "Create document", + "tags": [ + "Documents" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2CreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Document created and published successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2CreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded), or the `identifier` is already in use." + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to create a document on this model." + }, + "404": { + "description": "Base model or branch not found." + }, + "405": { + "description": "Method not allowed." + } + } + } + }, + "/api/v2/documents/{identifier}": { + "get": { + "description": "Read the document's published state — draft edits are never surfaced here. When a draft exists, read it via `GET /api/v2/documents/{identifier}/draft/{draftIdentifier}` before round-tripping the response into a draft PATCH, so you patch the draft's own content rather than published content over it. Returns the full `DocumentsV2ReadResponse` shape.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", + "operationId": "documentsV2Get", + "summary": "Read document state", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "example": "abc123" + }, + "required": true, + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "0", + "1", + "true", + "false" + ], + "description": "Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless." + }, + "required": false, + "description": "Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless.", + "name": "pretty", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Document state. A workbook-only document (no dashboard layout yet) returns only the workbook-scoped fields (`name`, `description`, `queryPresentations`); the dashboard-scoped `containers`, `controls`, and `settings` are omitted until a layout exists.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2ReadResponse" + } + } + } + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to read the document." + }, + "404": { + "description": "Document not found." + }, + "422": { + "description": "The document cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." + } + } + } + }, + "/api/v2/documents/{identifier}/draft": { + "patch": { + "description": "Create a new draft on the published document and apply the patch. No auto-publish — the response includes the new `draftIdentifier` for follow-up calls.\n\nPass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main (unpublished) workspace.", + "operationId": "documentsV2PatchDraft", + "summary": "Create draft and patch document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "example": "abc123" + }, + "required": true, + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2CreateDraftBody" + } + } + } + }, + "responses": { + "200": { + "description": "Draft created and patch applied successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded, or a `modelId` that differs from the document’s immutable base model)." + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to update the document." + }, + "404": { + "description": "Document or branch not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." + }, + "422": { + "description": "The document cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only document patched without a `containers` payload (or with an empty one)." + } + } + } + }, + "/api/v2/documents/{identifier}/draft/{draftIdentifier}": { + "get": { + "description": "Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape — same as the live-state read endpoint.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", + "operationId": "documentsV2GetDraft", + "summary": "Read draft state", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "example": "def456" + }, + "required": true, + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "name": "draftIdentifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Published document identifier.", + "example": "abc123" + }, + "required": true, + "description": "Published document identifier.", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "0", + "1", + "true", + "false" + ], + "description": "Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless." + }, + "required": false, + "description": "Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless.", + "name": "pretty", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Draft state.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2ReadResponse" + } + } + } + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to read the draft." + }, + "404": { + "description": "Document or draft not found." + }, + "422": { + "description": "The draft cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." + } + } + }, + "patch": { + "description": "Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply — no draft creation, no publish.", + "operationId": "documentsV2PatchDraftByIdentifier", + "summary": "Patch draft", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "example": "def456" + }, + "required": true, + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "name": "draftIdentifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Published document identifier.", + "example": "abc123" + }, + "required": true, + "description": "Published document identifier.", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" + } + } + } + }, + "responses": { + "200": { + "description": "Patch applied to draft successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded, or a `modelId` that differs from the document’s immutable base model)." + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to update the draft." + }, + "404": { + "description": "Document or draft not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." + }, + "422": { + "description": "The draft cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only draft patched without a `containers` payload (or with an empty one)." + } + } + } + }, + "/api/v2/documents/{identifier}/draft/publish": { + "post": { + "description": "Publish the document's current main (non-branch) draft, promoting it to the published version. No request body — the draft is consumed, so the response echoes the now-published document metadata.\n\nOnly the main draft is publishable here; a branch-attached draft is published by merging its branch (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft returns 404. Documents that require a pull request to publish return 400.", + "operationId": "documentsV2PublishDraft", + "summary": "Publish draft", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "example": "abc123" + }, + "required": true, + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Draft published successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PublishDraftResponse" + } + } + } + }, + "400": { + "description": "The document requires a pull request to publish (response detail: \"Can't publish because this document can only be edited through a branch\")." + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to publish the draft." + }, + "404": { + "description": "Document not found, or it has no main draft to publish (a branch-attached draft is published by merging its branch)." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document." + } + } + } + }, + "/api/v2/documents/{identifier}/identifier": { + "put": { + "description": "Rename a published document's identifier. The change is applied live and immediately — it does not go through the draft/publish workflow — and the former identifier is recorded in the document's rename history.\n\nOnly published documents can be renamed. A draft target returns 409; an unknown or archived target returns 404. The new identifier must be a valid slug (otherwise 400) and unused by any other document in the organization (otherwise 409).", + "operationId": "documentsV2UpdateIdentifier", + "summary": "Rename document identifier", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "example": "abc123" + }, + "required": true, + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2UpdateIdentifierBody" + } + } + } + }, + "responses": { + "200": { + "description": "Identifier updated successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2UpdateIdentifierResponse" + } + } + } + }, + "400": { + "description": "Invalid identifier format." + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to rename the document." + }, + "404": { + "description": "Document not found or archived." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is a draft rather than a published document, or the requested identifier is already in use by another document." + } + } + } + }, + "/api/v1/embed/sso/generate-session": { + "post": { + "operationId": "embedSsoGenerateSession", + "summary": "Generate embedded SSO session", + "tags": [ + "Embed" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbedSsoGenerateSessionBody" + } + } + } + }, + "responses": { + "200": { + "description": "Session token generated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbedSsoGenerateSessionResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required (API key with embed scope)" + }, + "403": { + "description": "Permission denied - embed not enabled" + } + } + } + }, + "/api/v1/ai/eval/prompt-sets": { + "get": { + "description": "List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt sets for every shared model the caller can access. Requires at least the Querier role on each requested model.", + "operationId": "aiEvalPromptSetsList", + "summary": "List eval prompt sets", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ], + "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "example": "false" + }, + "required": false, + "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "name": "archived", + "in": "query" + }, + { + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`)." + }, + "required": false, + "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`).", + "name": "model_ids", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of prompt sets, sorted alphabetically by name.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsListResponse" + } + } + } + }, + "400": { + "description": "Invalid query params (e.g. `model_ids` contains a non-UUID, or `archived` is not `true`/`false`).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. The caller must have at least the Querier role on each requested model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "No eval-accessible models for this caller.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + }, + "post": { + "description": "Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional prompts can be added later via PATCH.", + "operationId": "aiEvalPromptSetsCreate", + "summary": "Create an eval prompt set", + "tags": [ + "AI Eval" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Prompt set created successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. The caller must have at least the Querier role on the model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "422": { + "description": "Prompt count exceeds the organization's per-set cap (default 25, higher for orgs with the `ai-eval-extra-prompts` flag).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError422" + } + } + } + } + } + } + }, + "/api/v1/ai/eval/prompt-sets/{promptSetId}": { + "get": { + "description": "Get a single prompt set with all of its prompts.", + "operationId": "aiEvalPromptSetsGet", + "summary": "Get an eval prompt set", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Prompt set details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsGetResponse" + } + } + } + }, + "400": { + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + }, + "patch": { + "description": "Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully replaces the existing list — existing prompts omitted from the list are deleted, entries without an `id` are created, and entries with a matching `id` are updated in place.", + "operationId": "aiEvalPromptSetsUpdate", + "summary": "Update an eval prompt set", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Prompt set updated successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "422": { + "description": "A `prompts[].id` in the request does not belong to this prompt set, or the prompt count exceeds the organization's per-set cap (default 25, higher for orgs with the `ai-eval-extra-prompts` flag).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError422" + } + } + } + } + } + }, + "delete": { + "description": "Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight agentic job associated with the set; the returned `cancelled_job_count` reports how many were cancelled. The archive is committed before run cancellations start. Cancellation is best-effort — the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt set is already archived. The call is idempotent — retrying drains any remaining runs.", + "operationId": "aiEvalPromptSetsArchive", + "summary": "Archive an eval prompt set", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Prompt set archived successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsDeleteResponse" + } + } + } + }, + "400": { + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "500": { + "description": "Archive committed but a run-cancellation failed; the set is already archived — safe to retry.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } + } + } + } + }, + "/api/v1/ai/eval/prompt-sets/{promptSetId}/unarchive": { + "post": { + "description": "Restore an archived prompt set.", + "operationId": "aiEvalPromptSetsUnarchive", + "summary": "Restore an archived eval prompt set", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Prompt set restored successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsUnarchiveResponse" + } + } + } + }, + "400": { + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/eval/runs": { + "get": { + "description": "List runs for a prompt set, newest first, filtered to runs whose model the caller can access. The `prompt_set_id` query parameter is required.", + "operationId": "aiEvalRunsList", + "summary": "List eval runs", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ], + "description": "When `true`, returns archived runs instead of active ones. Defaults to `false`.", + "example": "false" + }, + "required": false, + "description": "When `true`, returns archived runs instead of active ones. Defaults to `false`.", + "name": "archived", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Required — the prompt set whose runs should be listed.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Required — the prompt set whose runs should be listed.", + "name": "prompt_set_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of runs for the prompt set.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsListResponse" + } + } + } + }, + "400": { + "description": "Missing or invalid `prompt_set_id`.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + }, + "post": { + "description": "Create and start a new run against an existing prompt set. The run enqueues one agentic job per prompt and begins executing immediately. Returns the newly created run with its initial per-prompt result rows.", + "operationId": "aiEvalRunsCreate", + "summary": "Start an eval run", + "tags": [ + "AI Eval" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Run created and jobs enqueued.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. The caller must have at least the Querier role on the prompt set's model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "The prompt set was not found, or `run_config.branch_id` does not match an existing branch in the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "422": { + "description": "`run_config.branch_id` does not belong to the prompt set's model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError422" + } + } + } + }, + "429": { + "description": "Per-user active-run cap reached.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError429" + } + } + } + }, + "500": { + "description": "Run created and jobs enqueued, but it could not be re-read for the response. The run exists — list runs for the prompt set to find it rather than retrying, since a retry starts a duplicate run.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } + }, + "503": { + "description": "AI eval is paused for this organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError503" + } + } + } + } + } + } + }, + "/api/v1/ai/eval/runs/{runId}": { + "get": { + "description": "Get an eval run with every per-prompt result row, including the underlying agentic job state and any scoring data.", + "operationId": "aiEvalRunsGet", + "summary": "Get an eval run", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "The unique identifier of the eval run.", + "name": "runId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Run detail.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsGetResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Run not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + }, + "delete": { + "description": "Archive (soft-delete) an eval run. Any non-terminal per-prompt agentic jobs are cancelled as part of the archive (best-effort), and a still-RUNNING run is flipped to CANCELLED before archival. The call is idempotent; archiving an already-terminal or already-archived run is a no-op.", + "operationId": "aiEvalRunsArchive", + "summary": "Archive an eval run", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "The unique identifier of the eval run.", + "name": "runId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Run archived successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsDeleteResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Run not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "500": { + "description": "A still-running run may already be flipped to CANCELLED and archived even though the rest of the cascade failed — safe to retry.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } + } + } + } + }, + "/api/v1/ai/eval/runs/{runId}/cancel": { + "post": { + "description": "Cancel an in-flight eval run. Any non-terminal per-prompt jobs are cancelled and the run is archived — the response returns the updated run inline (`status: CANCELLED`, `is_archived: true`); use `/unarchive` to surface it in the default `archived=false` list again.", + "operationId": "aiEvalRunsCancel", + "summary": "Cancel an eval run", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "The unique identifier of the eval run.", + "name": "runId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Cancellation processed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsCancelResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Run not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "500": { + "description": "The run was cancelled and archived, but could not be re-read for the response — safe to retry.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } + } + } + } + }, + "/api/v1/ai/eval/runs/{runId}/unarchive": { + "post": { + "description": "Restore an archived eval run.", + "operationId": "aiEvalRunsUnarchive", + "summary": "Restore an archived eval run", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "The unique identifier of the eval run.", + "name": "runId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Run restored successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsUnarchiveResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Run not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + } + }, + "/api/v1/folders": { + "get": { + "operationId": "foldersList", + "summary": "List folders", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination" + }, + "required": false, + "description": "Cursor for pagination", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of fields to include (_count, labels, onlySharedWithMe). onlySharedWithMe returns only folders shared with the user, cannot be combined with ownerId or path, and when used with org-scoped API keys requires the userId query parameter. For user-scoped keys (PAT), userId is auto-inferred from the token.", + "example": "_count,labels" + }, + "required": false, + "description": "Comma-separated list of fields to include (_count, labels, onlySharedWithMe). onlySharedWithMe returns only folders shared with the user, cannot be combined with ownerId or path, and when used with org-scoped API keys requires the userId query parameter. For user-scoped keys (PAT), userId is auto-inferred from the token.", + "name": "include", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of labels to filter by" + }, + "required": false, + "description": "Comma-separated list of labels to filter by", + "name": "labels", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by owner user ID" + }, + "required": false, + "description": "Filter by owner user ID", + "name": "ownerId", + "in": "query" + }, + { + "schema": { + "type": [ + "number", + "null" + ], + "description": "Number of results per page", + "example": 20 + }, + "required": false, + "description": "Number of results per page", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by exact path" + }, + "required": false, + "description": "Filter by exact path", + "name": "path", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Filter by share scope" + }, + "required": false, + "description": "Filter by share scope", + "name": "scope", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name", + "createdAt", + "updatedAt", + "favorites", + "path" + ], + "description": "Field to sort by" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "User membership ID. Only used with onlySharedWithMe include field. Required for org-scoped API keys; auto-inferred from the token for user-scoped keys (PAT)." + }, + "required": false, + "description": "User membership ID. Only used with onlySharedWithMe include field. Required for org-scoped API keys; auto-inferred from the token for user-scoped keys (PAT).", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of folders", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Folder not found (when filtering by path)" + } + } + }, + "post": { + "operationId": "foldersCreate", + "summary": "Create a folder", + "tags": [ + "Folders" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Folder created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body, scope mismatch with parent folder, or cannot create under restricted folder owned by another user" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Parent folder not found" + } + } + } + }, + "/api/v1/folders/{folderId}": { + "delete": { + "description": "Deletes a folder. By default, non-empty folders (containing documents or sub-folders) return a 400 error. Pass `force=true` to recursively archive all documents (soft-delete to trash) and permanently remove all sub-folders before deleting the target folder. Force delete is limited to 100 total items (documents + sub-folders).", + "operationId": "foldersDelete", + "summary": "Delete a folder", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the folder", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Unique identifier for the folder", + "name": "folderId", + "in": "path" + }, + { + "schema": { + "type": [ + "boolean", + "null" + ], + "default": false, + "description": "When true, recursively deletes all documents (sent to trash) and sub-folders within the folder. Limited to 100 total items (documents + sub-folders)." + }, + "required": false, + "description": "When true, recursively deletes all documents (sent to trash) and sub-folders within the folder. Limited to 100 total items (documents + sub-folders).", + "name": "force", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Folder deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersDeleteResponse" + } + } + } + }, + "400": { + "description": "Folder cannot be deleted (e.g., contains documents or sub-folders and force is not set, or force delete exceeds the 100-item limit)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - cannot view or delete folder" + }, + "404": { + "description": "Folder not found" + } + } + }, + "patch": { + "description": "Update a folder's display name and/or URL path segment. At least one of `name` or `path` must be provided. Changing the name does not automatically update the path. When the path is updated, descendant folder paths are cascaded.", + "operationId": "foldersUpdate", + "summary": "Update a folder", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the folder", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Unique identifier for the folder", + "name": "folderId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Folder updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body (empty name, invalid path characters, reserved path, or neither field provided)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - EDITOR role required" + }, + "404": { + "description": "Folder not found" + }, + "409": { + "description": "Path conflicts with an existing folder (when resolvePathConflict is false)" + } + } + } + }, + "/api/v1/folders/{folderId}/permissions": { + "get": { + "operationId": "foldersGetPermissions", + "summary": "Get folder permissions", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the folder", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Unique identifier for the folder", + "name": "folderId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter permits for a specific user. If omitted, returns all permits (requires MANAGER role)." + }, + "required": false, + "description": "Filter permits for a specific user. If omitted, returns all permits (requires MANAGER role).", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Folder permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersGetPermissionsResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - VIEWER role required to view specific user permissions, MANAGER role required to list all" + }, + "404": { + "description": "Folder or user not found" + } + } + }, + "post": { + "operationId": "foldersAddPermissions", + "summary": "Add folder permissions", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the folder", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Unique identifier for the folder", + "name": "folderId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersAddPermissionsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permissions added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersAddPermissionsResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds must be provided" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Folder not found" + } + } + }, + "patch": { + "operationId": "foldersUpdatePermissions", + "summary": "Update folder permissions", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the folder", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Unique identifier for the folder", + "name": "folderId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersUpdatePermissionsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permissions updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersUpdatePermissionsResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds must be provided" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Folder not found" + } + } + }, + "delete": { + "operationId": "foldersRevokePermissions", + "summary": "Revoke folder permissions", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the folder", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Unique identifier for the folder", + "name": "folderId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersRevokePermissionsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permissions revoked successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersRevokePermissionsResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds must be provided" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Folder not found" + } + } + } + }, + "/api/v1/labels": { + "get": { + "operationId": "labelsList", + "summary": "List all labels", + "tags": [ + "Labels" + ], + "responses": { + "200": { + "description": "List of all labels in the organization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + } + } + }, + "post": { + "operationId": "labelsCreate", + "summary": "Create a label", + "tags": [ + "Labels" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Label created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - cannot create verified/homepage labels without admin permissions" + }, + "409": { + "description": "Label with this name already exists" + } + } + } + }, + "/api/v1/labels/{name}": { + "get": { + "operationId": "labelsGet", + "summary": "Get a label by name", + "tags": [ + "Labels" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "name", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Label details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Label not found" + } + } + }, + "put": { + "operationId": "labelsUpdate", + "summary": "Update a label", + "tags": [ + "Labels" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "name", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Label updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - cannot modify verified/homepage labels without admin permissions" + }, + "404": { + "description": "Label not found" + }, + "409": { + "description": "Label with new name already exists" + } + } + }, + "delete": { + "operationId": "labelsDelete", + "summary": "Delete a label", + "tags": [ + "Labels" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "name", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Label deleted successfully" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - cannot delete verified/homepage labels without admin permissions" + }, + "404": { + "description": "Label not found" + }, + "409": { + "description": "Cannot delete label that is applied to documents" + } + } + } + }, + "/api/v1/models/{modelId}/suggestions": { + "get": { + "description": "Lists AI-generated model suggestions for a shared model, filtered by dismissal status. Requires organization admin permissions.", + "operationId": "modelSuggestionsList", + "summary": "List model suggestions", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestions belong to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestions belong to", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Cursor for pagination: the `nextCursor` from the previous response (the last suggestion id)." + }, + "required": false, + "description": "Cursor for pagination: the `nextCursor` from the previous response (the last suggestion id).", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "active", + "ignored", + "all" + ], + "default": "active", + "description": "Which suggestions to return: `active` (default, not dismissed), `ignored` (dismissed only), or `all`.", + "example": "active" + }, + "required": false, + "description": "Which suggestions to return: `active` (default, not dismissed), `ignored` (dismissed only), or `all`.", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of suggestions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelSuggestionsListResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters or malformed `modelId`" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Model not found in this organization" + } + } + } + }, + "/api/v1/models/{modelId}/suggestions/schedule": { + "put": { + "description": "Enables the daily schedule that generates suggestions for the shared model. Idempotent — re-enabling leaves an existing schedule untouched. Requires organization admin permissions.", + "operationId": "modelSuggestionsScheduleEnable", + "summary": "Enable the suggestion schedule", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestions belong to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestions belong to", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScheduleSuggestionsBody" + } + } + } + }, + "responses": { + "200": { + "description": "The schedule is enabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScheduleSuggestionsResponse" + } + } + } + }, + "400": { + "description": "Invalid timezone or malformed `modelId`" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Model not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + }, + "delete": { + "description": "Disables the daily generation schedule for the shared model. Idempotent. Requires organization admin permissions.", + "operationId": "modelSuggestionsScheduleDisable", + "summary": "Disable the suggestion schedule", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestions belong to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestions belong to", + "name": "modelId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The schedule is disabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Malformed `modelId`" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Model not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + } + }, + "/api/v1/models/{modelId}/suggestions/{suggestionId}/ignore": { + "post": { + "description": "Dismisses (ignores) a suggestion, optionally with a reason. Requires organization admin permissions.", + "operationId": "modelSuggestionsIgnore", + "summary": "Ignore a suggestion", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestion belongs to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestion belongs to", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the suggestion", + "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" + }, + "required": true, + "description": "UUID of the suggestion", + "name": "suggestionId", + "in": "path" + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IgnoreSuggestionBody" + } + } + } + }, + "responses": { + "200": { + "description": "The suggestion was dismissed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid body or malformed id" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Suggestion or model not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + } + }, + "/api/v1/models/{modelId}/suggestions/{suggestionId}/restore": { + "post": { + "description": "Restores a previously dismissed suggestion back to the active list. Requires organization admin permissions.", + "operationId": "modelSuggestionsRestore", + "summary": "Restore a suggestion", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestion belongs to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestion belongs to", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the suggestion", + "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" + }, + "required": true, + "description": "UUID of the suggestion", + "name": "suggestionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The suggestion was restored", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Malformed id" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Suggestion or model not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + } + }, + "/api/v1/models/{modelId}/suggestions/{suggestionId}": { + "delete": { + "description": "Permanently deletes a suggestion. Requires organization admin permissions.", + "operationId": "modelSuggestionsDelete", + "summary": "Delete a suggestion", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestion belongs to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestion belongs to", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the suggestion", + "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" + }, + "required": true, + "description": "UUID of the suggestion", + "name": "suggestionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The suggestion was deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Malformed id" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Suggestion or model not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + } + }, + "/api/v1/models": { + "get": { + "operationId": "modelsList", + "summary": "List models", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by base model ID" + }, + "required": false, + "description": "Filter by base model ID", + "name": "baseModelId", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by connection ID" + }, + "required": false, + "description": "Filter by connection ID", + "name": "connectionId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination" + }, + "required": false, + "description": "Cursor for pagination", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of fields to include (e.g., activeBranches)", + "example": "activeBranches" + }, + "required": false, + "description": "Comma-separated list of fields to include (e.g., activeBranches)", + "name": "include", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "0", + "1", + "true", + "false" + ], + "description": "Include deleted models" + }, + "required": false, + "description": "Include deleted models", + "name": "includeDeleted", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by specific model ID" + }, + "required": false, + "description": "Filter by specific model ID", + "name": "modelId", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "SCHEMA", + "SHARED", + "SHARED_EXTENSION", + "BRANCH", + "WORKBOOK", + "QUERY" + ], + "description": "Filter by model kind" + }, + "required": false, + "description": "Filter by model kind", + "name": "modelKind", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by model name" + }, + "required": false, + "description": "Filter by model name", + "name": "name", + "in": "query" + }, + { + "schema": { + "type": "integer", + "exclusiveMinimum": 0, + "description": "Number of results per page", + "example": 20 + }, + "required": false, + "description": "Number of results per page", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name", + "modelKind", + "connectionId", + "baseModelId", + "createdAt", + "updatedAt" + ], + "description": "Field to sort by" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of models", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + } + } + }, + "post": { + "description": "Create a new model. Supports creating schema, shared, branch, and shared_extension models.", + "operationId": "modelsCreate", + "summary": "Create model", + "tags": [ + "Models" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateModelSchemaBase" + } + } + } + }, + "responses": { + "200": { + "description": "Model created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "Error message if creation failed" + }, + "message": { + "type": "string", + "description": "Additional message" + }, + "model": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Created model ID" + }, + "modelKind": { + "type": "string", + "description": "Kind of model created" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Model name" + } + }, + "required": [ + "id", + "modelKind", + "name" + ], + "description": "Created model details" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + } + }, + "required": [ + "success" + ], + "description": "Create model response", + "title": "ModelsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or model creation not allowed" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Connection or base model not found" + } + } + } + }, + "/api/v1/models/{modelId}": { + "patch": { + "description": "Update metadata for an existing model. Currently supports renaming the model via the `name` field.", + "operationId": "modelsUpdate", + "summary": "Update model", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Model updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/jobs/{jobId}/status": { + "get": { + "description": "Check status of a schema refresh job (POST /api/v1/models/{modelId}/refresh) or a dbt sync job (POST /api/v1/models/{modelId}/dbt-sync). Returns IN_PROGRESS, COMPLETED, or FAILED.", + "operationId": "jobsGetStatus", + "summary": "Get schema refresh or dbt sync job status", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "The job ID returned from a job creation endpoint (e.g., POST /api/v1/models/{modelId}/refresh)", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "The job ID returned from a job creation endpoint (e.g., POST /api/v1/models/{modelId}/refresh)", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Job status (IN_PROGRESS, COMPLETED, or FAILED)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JobsGetStatusResponse" + } + } + } + }, + "400": { + "description": "Unsupported job type (only schema refresh and dbt sync supported)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection READ permission required" + }, + "404": { + "description": "Job not found" + } + } + } + }, + "/api/v1/models/{modelId}/schemas": { + "get": { + "operationId": "modelsGetSchemas", + "summary": "List available schemas for a model", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of available schemas", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGetSchemasResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/view": { + "get": { + "operationId": "modelsGetViews", + "summary": "Get model views", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of views in the model", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGetViewResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/view/{viewName}": { + "patch": { + "operationId": "modelsUpdateView", + "summary": "Update view", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "View name", + "example": "orders" + }, + "required": true, + "description": "View name", + "name": "viewName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsUpdateViewBody" + } + } + } + }, + "responses": { + "200": { + "description": "View updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or view not found" + } + } + }, + "delete": { + "operationId": "modelsDeleteView", + "summary": "Delete view", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "View name", + "example": "orders" + }, + "required": true, + "description": "View name", + "name": "viewName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "COMBINED", + "MERGED", + "EXTENSION" + ], + "description": "Controls delete behavior to match IDE editing modes. COMBINED (default) marks the view as ignored if it exists in the parent model, otherwise hard-deletes. MERGED marks the view as shallowIgnored (hidden only from the immediate parent). EXTENSION hard-deletes the view from the extension layer.", + "example": "COMBINED" + }, + "required": false, + "description": "Controls delete behavior to match IDE editing modes. COMBINED (default) marks the view as ignored if it exists in the parent model, otherwise hard-deletes. MERGED marks the view as shallowIgnored (hidden only from the immediate parent). EXTENSION hard-deletes the view from the extension layer.", + "name": "mode", + "in": "query" + } + ], + "responses": { + "200": { + "description": "View deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or view not found" + } + } + } + }, + "/api/v1/models/{modelId}/view/{viewName}/field/{fieldName}": { + "patch": { + "operationId": "modelsUpdateField", + "summary": "Update field", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "View name", + "example": "orders" + }, + "required": true, + "description": "View name", + "name": "viewName", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Field name", + "example": "total_amount" + }, + "required": true, + "description": "Field name", + "name": "fieldName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsUpdateFieldBody" + } + } + } + }, + "responses": { + "200": { + "description": "Field updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model, view, or field not found" + } + } + }, + "delete": { + "operationId": "modelsDeleteField", + "summary": "Delete field", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "View name", + "example": "orders" + }, + "required": true, + "description": "View name", + "name": "viewName", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Field name", + "example": "total_amount" + }, + "required": true, + "description": "Field name", + "name": "fieldName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID" + }, + "required": false, + "description": "Branch ID", + "name": "branch_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Topic context for the field" + }, + "required": false, + "description": "Topic context for the field", + "name": "topic_context", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Field deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model, view, or field not found" + } + } + } + }, + "/api/v1/models/{modelId}/topic": { + "get": { + "operationId": "modelsListTopics", + "summary": "List topics", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of topics in the model", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsListTopicsResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/topic/{topicName}": { + "get": { + "operationId": "modelsGetTopic", + "summary": "Get topic", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Topic name", + "example": "sales_analytics" + }, + "required": true, + "description": "Topic name", + "name": "topicName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Topic details with relationships and views", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGetTopicResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or topic not found" + } + } + }, + "patch": { + "operationId": "modelsUpdateTopic", + "summary": "Update topic", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Topic name", + "example": "sales_analytics" + }, + "required": true, + "description": "Topic name", + "name": "topicName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsUpdateTopicBody" + } + } + } + }, + "responses": { + "200": { + "description": "Topic updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or topic not found" + } + } + }, + "delete": { + "operationId": "modelsDeleteTopic", + "summary": "Delete topic", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Topic name", + "example": "sales_analytics" + }, + "required": true, + "description": "Topic name", + "name": "topicName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "COMBINED", + "MERGED", + "EXTENSION" + ], + "description": "Controls delete behavior to match IDE editing modes. COMBINED (default) adds the topic to deletedTopics if it exists in the parent model (prevents reappearing). MERGED behaves the same as COMBINED. EXTENSION hard-deletes the topic from the extension layer.", + "example": "COMBINED" + }, + "required": false, + "description": "Controls delete behavior to match IDE editing modes. COMBINED (default) adds the topic to deletedTopics if it exists in the parent model (prevents reappearing). MERGED behaves the same as COMBINED. EXTENSION hard-deletes the topic from the extension layer.", + "name": "mode", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Topic deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or topic not found" + } + } + } + }, + "/api/v1/models/{modelId}/field": { + "post": { + "operationId": "modelsCreateField", + "summary": "Create field", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsCreateFieldBody" + } + } + } + }, + "responses": { + "201": { + "description": "Field created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or view not found" + } + } + } + }, + "/api/v1/models/{modelId}/refresh": { + "post": { + "operationId": "modelsRefresh", + "summary": "Refresh model schema", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID for branch-based schema refresh. Required when branch-based schema refresh is enabled for the connection. Must not be provided when branch-based schema refresh is not enabled.", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID for branch-based schema refresh. Required when branch-based schema refresh is enabled for the connection. Must not be provided when branch-based schema refresh is not enabled.", + "name": "branch_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ], + "description": "When true (the default), performs a hard refresh that fully discards and rebuilds the schema model. When false, performs a soft refresh that merges newly generated views with the existing model. Must be set to false when `schemas` or `tables` filters are provided.", + "example": "false" + }, + "required": false, + "description": "When true (the default), performs a hard refresh that fully discards and rebuilds the schema model. When false, performs a soft refresh that merges newly generated views with the existing model. Must be set to false when `schemas` or `tables` filters are provided.", + "name": "hard_refresh", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Optional comma-separated list of schemas to refresh selectively. Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "example": "public,analytics" + }, + "required": false, + "description": "Optional comma-separated list of schemas to refresh selectively. Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "name": "schemas", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Optional comma-separated list of tables to refresh selectively. Only the listed tables are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "example": "public.orders,public.customers" + }, + "required": false, + "description": "Optional comma-separated list of tables to refresh selectively. Only the listed tables are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "name": "tables", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Refresh job started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsRefreshResponse" + } + } + } + }, + "400": { + "description": "Bad request - branch_id required when branch-based schema refresh is enabled, branch_id not allowed when it is not enabled, or hard refresh requested with selective schemas/tables filters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/validate": { + "get": { + "operationId": "modelsValidate", + "summary": "Validate model", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to validate" + }, + "required": false, + "description": "Branch ID to validate", + "name": "branchId", + "in": "query" + }, + { + "schema": { + "type": "integer", + "exclusiveMinimum": 0, + "description": "Maximum number of validation issues to return" + }, + "required": false, + "description": "Maximum number of validation issues to return", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Validation results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsValidateResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/migrate": { + "post": { + "operationId": "modelsMigrate", + "summary": "Migrate model", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsMigrateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Migration completed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or migration not allowed" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/branch/{branchName}": { + "delete": { + "operationId": "modelsDeleteBranch", + "summary": "Delete branch", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Branch name", + "example": "feature/new-metrics" + }, + "required": true, + "description": "Branch name", + "name": "branchName", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Branch deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or branch not found" + } + } + } + }, + "/api/v1/models/{modelId}/dbt-exposures": { + "get": { + "description": "Returns the dbt exposures for a model, computed on-demand by analyzing which dbt models are referenced by dashboards that use this model. Returns exactly one record per dashboard. The exposure field is null when a dashboard does not reference any dbt models. Exposure names (exposure.name) may contain duplicates when multiple dashboards produce the same name; use deduplication_name for a guaranteed-unique value, or use it as a fallback when names collide.", + "operationId": "modelsDbtExposures", + "summary": "Get dbt exposures", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Field to sort results by" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of dbt exposures for the model", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsDbtExposuresResponse" + } + } + } + }, + "400": { + "description": "Invalid request parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/branch/{branchName}/dbt": { + "post": { + "description": "Set the active dbt environment on a branch.", + "operationId": "modelsBranchDbt", + "summary": "Set branch dbt environment", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Branch name", + "example": "feature/new-metrics" + }, + "required": true, + "description": "Branch name", + "name": "branchName", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsBranchDbtBody" + } + } + } + }, + "responses": { + "200": { + "description": "dbt environment set successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or branch not found" + } + } + } + }, + "/api/v1/models/{modelId}/dbt-sync": { + "post": { + "description": "Trigger a dbt metadata sync (\"dbt quick sync\") for a branch. Recompiles the branch's dbt manifest and merges the regenerated dbt extension model, without a full database schema scan. The branch (via branch_id) supplies the dbt environment and dbt git branch. Runs as a background job.", + "operationId": "modelsDbtSync", + "summary": "Trigger a dbt metadata sync for a branch", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "ID of the branch to sync dbt metadata for. The branch supplies the dbt environment and dbt git branch to compile against (set via POST /api/v1/models/{modelId}/branch/{branchName}/dbt).", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": true, + "description": "ID of the branch to sync dbt metadata for. The branch supplies the dbt environment and dbt git branch to compile against (set via POST /api/v1/models/{modelId}/branch/{branchName}/dbt).", + "name": "branch_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "dbt sync job started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JobCreatedResponse" + } + } + } + }, + "400": { + "description": "Invalid request parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or branch not found, or model deleted" + }, + "405": { + "description": "Method not allowed" + }, + "422": { + "description": "The model is not a shared model" + } + } + } + }, + "/api/v1/models/{modelId}/branch/{branchName}/merge": { + "post": { + "operationId": "modelsMergeBranch", + "summary": "Merge branch", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Branch name", + "example": "feature/new-metrics" + }, + "required": true, + "description": "Branch name", + "name": "branchName", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsMergeBranchBody" + } + } + } + }, + "responses": { + "200": { + "description": "Branch merged successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsMergeBranchResponse" + } + } + } + }, + "400": { + "description": "Invalid request body, merge not allowed, or merge conflict" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or PR required" + }, + "404": { + "description": "Model or branch not found" + } + } + } + }, + "/api/v1/models/{modelId}/git/commit": { + "post": { + "description": "Push the branch contents to git and create or update a pull request. The backend automatically detects whether the git branch already exists: if not, it creates a new git branch and opens a PR; if it does, it commits the latest model contents to the existing branch (updating the open PR).", + "operationId": "modelsCommit", + "summary": "Commit branch to git", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsCommitBody" + } + } + } + }, + "responses": { + "200": { + "description": "Branch committed to git and pull request created or updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsCommitResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or git not configured" + }, + "404": { + "description": "Model or branch not found" + } + } + } + }, + "/api/v1/models/{modelId}/cache_reset/{policyName}": { + "post": { + "operationId": "modelsCacheReset", + "summary": "Reset cache for policy", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cache policy name", + "example": "daily_refresh" + }, + "required": true, + "description": "Cache policy name", + "name": "policyName", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsCacheResetBody" + } + } + } + }, + "responses": { + "200": { + "description": "Cache reset scheduled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsCacheResetResponse" + } + } + } + }, + "400": { + "description": "Invalid reset timestamp" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or cache policy not found" + } + } + } + }, + "/api/v1/models/{modelId}/git": { + "get": { + "operationId": "modelsGitGet", + "summary": "Get git configuration", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of optional fields to include. Supported: \"webhookSecret\"", + "example": "webhookSecret" + }, + "required": false, + "description": "Comma-separated list of optional fields to include. Supported: \"webhookSecret\"", + "name": "include", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Git configuration for the model", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found or git not configured" + } + } + }, + "post": { + "operationId": "modelsGitCreate", + "summary": "Create git configuration", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Git configuration created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid SSH URL or configuration" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + }, + "409": { + "description": "Git already configured for this model" + } + } + }, + "patch": { + "operationId": "modelsGitUpdate", + "summary": "Update git configuration", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Git configuration updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid SSH URL or configuration" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found or git not configured" + } + } + }, + "delete": { + "operationId": "modelsGitDelete", + "summary": "Delete git configuration", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Git configuration deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found or git not configured" + } + } + } + }, + "/api/v1/models/{modelId}/git/sync": { + "post": { + "operationId": "modelsGitSync", + "summary": "Sync model with git", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitSyncBody" + } + } + } + }, + "responses": { + "200": { + "description": "Sync status and result (includes inSync=false for conflicts requiring manual resolution)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitSyncResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or git not configured" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/content-validator": { + "get": { + "operationId": "modelsContentValidatorGet", + "summary": "Validate content references", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID to validate against. Non-UUID values return 400." + }, + "required": false, + "description": "Optional branch ID to validate against. Non-UUID values return 400.", + "name": "branch_id", + "in": "query" + }, + { + "schema": { + "$ref": "#/components/schemas/ContentFilterMode" + }, + "required": false, + "description": "Filter documents by issue status. ALL (default) returns all documents with at least one query. WITH_ISSUES returns only documents with at least one query issue, dashboard filter issue, or document error. NO_ISSUES returns only documents with zero issues and no document errors.", + "name": "content_filter_mode", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter to documents created by this user (user ID). Unknown IDs return 400." + }, + "required": false, + "description": "Filter to documents created by this user (user ID). Unknown IDs return 400.", + "name": "creator_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "description": "Optional value to find. Used with find_type to scope validation to a single view, field, or topic. Requires find_type to be provided." + }, + "required": false, + "description": "Optional value to find. Used with find_type to scope validation to a single view, field, or topic. Requires find_type to be provided.", + "name": "find", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "FIELD", + "TOPIC", + "VIEW" + ], + "description": "Optional type of find operation (VIEW, FIELD, TOPIC). Requires find to be provided. FIELD values must be scoped by view name (e.g. view_name.field_name)." + }, + "required": false, + "description": "Optional type of find operation (VIEW, FIELD, TOPIC). Requires find to be provided. FIELD values must be scoped by view name (e.g. view_name.field_name).", + "name": "find_type", + "in": "query" + }, + { + "schema": { + "type": "array", + "description": "Prefix-match folder paths. \"/Finance\" matches \"/Finance/Reports\". Documents with no folder are excluded unless \"\" is specified.", + "items": { + "type": "string" + } + }, + "required": false, + "description": "Prefix-match folder paths. \"/Finance\" matches \"/Finance/Reports\". Documents with no folder are excluded unless \"\" is specified.", + "name": "folder_paths", + "in": "query" + }, + { + "schema": { + "type": "boolean", + "description": "Whether to include personal folders in validation" + }, + "required": false, + "description": "Whether to include personal folders in validation", + "name": "include_personal_folders", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated label names. Documents matching any label are included. Unknown labels return 400." + }, + "required": false, + "description": "Comma-separated label names. Documents matching any label are included. Unknown labels return 400.", + "name": "labels", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Optional user ID for scoping" + }, + "required": false, + "description": "Optional user ID for scoping", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Content validation results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsContentValidatorGetResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters or unknown labels" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + }, + "post": { + "operationId": "modelsContentValidatorReplace", + "summary": "Replace content references", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsContentValidatorReplaceBody" + } + } + } + }, + "responses": { + "200": { + "description": "Replace operation completed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsContentValidatorReplaceResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/yaml": { + "get": { + "operationId": "modelsYamlGet", + "summary": "Get model YAML", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID for branch-aware operations" + }, + "required": false, + "description": "Branch ID for branch-aware operations", + "name": "branchId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "File name to operate on" + }, + "required": false, + "description": "File name to operate on", + "name": "fileName", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "combined", + "extension", + "staged", + "merged", + "fully-resolved" + ], + "default": "combined", + "description": "IDE mode for YAML operations" + }, + "required": false, + "description": "IDE mode for YAML operations", + "name": "mode", + "in": "query" + }, + { + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ], + "default": false, + "description": "Resolve the model extends chain so the returned YAML reflects what runs at query time. Only valid with mode=combined." + }, + "required": false, + "description": "Resolve the model extends chain so the returned YAML reflects what runs at query time. Only valid with mode=combined.", + "name": "fullyResolved", + "in": "query" + }, + { + "schema": { + "type": [ + "boolean", + "null" + ], + "default": false, + "description": "Include checksums in response" + }, + "required": false, + "description": "Include checksums in response", + "name": "includeChecksums", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "A single schema name (optionally catalog-scoped, e.g. 'warehouse.reporting') to additionally load into the response. Use this to include view YAML from a schema that isn't active in the model (inactive or offloaded). Only views from this schema will be returned (views with no schema are always included)." + }, + "required": false, + "description": "A single schema name (optionally catalog-scoped, e.g. 'warehouse.reporting') to additionally load into the response. Use this to include view YAML from a schema that isn't active in the model (inactive or offloaded). Only views from this schema will be returned (views with no schema are always included).", + "name": "includeSchemas", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Model YAML content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelYamlResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + }, + "post": { + "operationId": "modelsYamlCreate", + "summary": "Update model YAML", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelYamlCreateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "Model YAML updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelYamlResponse" + } + } + } + }, + "400": { + "description": "Invalid YAML or file name" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + }, + "409": { + "description": "Checksum mismatch (concurrent modification)" + } + } + }, + "delete": { + "operationId": "modelsYamlDelete", + "summary": "Delete model YAML file", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID for branch-aware operations" + }, + "required": false, + "description": "Branch ID for branch-aware operations", + "name": "branchId", + "in": "query" + }, + { + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "description": "File name to delete (must end with '.topic' or '.view')" + }, + "required": true, + "description": "File name to delete (must end with '.topic' or '.view')", + "name": "fileName", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "combined", + "extension", + "staged", + "merged", + "fully-resolved" + ], + "default": "combined", + "description": "IDE mode for YAML operations" + }, + "required": false, + "description": "IDE mode for YAML operations", + "name": "mode", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Commit message for git sync" + }, + "required": false, + "description": "Commit message for git sync", + "name": "commitMessage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "YAML file deleted" + }, + "400": { + "description": "Invalid file name" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or file not found" + } + } + } + }, + "/api/v1/models/{modelId}/ai-agent-actions": { + "get": { + "description": "Returns the AI agent actions configured for this model — a unified list of sample queries and skills suitable for surfacing as suggested prompts above an AI prompt input. Sample queries come from both `model.sample_queries` and each topic's `sample_queries`; skills come from `model.skills` and each topic's `skills`, deduped by id with topic skills overriding model skills. Each entry's `prompt` is ready to submit verbatim to `POST /api/v1/ai/jobs`.", + "operationId": "modelAiAgentActions", + "summary": "Get model AI agent actions", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "AI agent actions in display order.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiAgentActionsResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key." + }, + "403": { + "description": "Caller cannot read the model." + }, + "404": { + "description": "Model not found." + } + } + } + }, + "/api/v1/query/run": { + "post": { + "operationId": "queryRun", + "summary": "Execute a semantic query", + "tags": [ + "Query" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryRunBody" + } + } + } + }, + "responses": { + "200": { + "description": "Query executed or started successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryRunResponse" + } + } + } + }, + "400": { + "description": "Invalid query definition or conflicting parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - querier role required on the model" + }, + "404": { + "description": "Model, topic, view, or branch not found" + }, + "408": { + "description": "Query timed out. The response includes remaining_job_ids that can be polled via the query/wait endpoint.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryTimeoutResponse" + } + } + } + }, + "500": { + "description": "Query execution error" + } + } + } + }, + "/api/v1/query/wait": { + "get": { + "operationId": "queryWait", + "summary": "Wait for query jobs to complete", + "tags": [ + "Query" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Comma-separated list of job IDs to wait for. Obtained from the query/run response.", + "example": "job_abc123,job_def456" + }, + "required": true, + "description": "Comma-separated list of job IDs to wait for. Obtained from the query/run response.", + "name": "jobIds", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Query results for completed jobs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryWaitResponse" + } + } + } + }, + "400": { + "description": "Invalid or missing jobIds parameter" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Job ID not found" + }, + "500": { + "description": "Error fetching query results" + } + } + } + }, + "/api/v1/schedules": { + "get": { + "operationId": "schedulesList", + "summary": "List schedules", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "default": 1, + "description": "The page number for offset-based pagination.", + "example": 1 + }, + "required": false, + "description": "The page number for offset-based pagination.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "The direction to sort results (asc or desc).", + "example": "desc" + }, + "required": false, + "description": "The direction to sort results (asc or desc).", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "scheduleName", + "dashboardName", + "ownerName", + "lastRun", + "lastRunStatus" + ], + "default": "scheduleName", + "description": "The field to sort results by. Valid values: scheduleName, dashboardName, ownerName, lastRun, lastRunStatus.", + "example": "scheduleName" + }, + "required": false, + "description": "The field to sort results by. Valid values: scheduleName, dashboardName, ownerName, lastRun, lastRunStatus.", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "dashboard", + "single tile" + ], + "description": "Filter schedules by content type: dashboard, single tile.", + "example": "dashboard" + }, + "required": false, + "description": "Filter schedules by content type: dashboard, single tile.", + "name": "contentType", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter schedules by embed entity." + }, + "required": false, + "description": "Filter schedules by embed entity.", + "name": "embedEntity", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "email", + "google_sheets", + "s3", + "sftp", + "slack", + "webhook" + ], + "description": "Filter schedules by destination type: email, slack, webhook, sftp, s3.", + "example": "email" + }, + "required": false, + "description": "Filter schedules by destination type: email, slack, webhook, sftp, s3.", + "name": "destination", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter schedules by the document's unique identifier. Can be found in the dashboard's URL after /dashboards/.", + "example": "12db1a0a" + }, + "required": false, + "description": "Filter schedules by the document's unique identifier. Can be found in the dashboard's URL after /dashboards/.", + "name": "identifier", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter schedules by the owner's user ID. Use the List users endpoint to retrieve user IDs.", + "example": "987fcdeb-51a2-43d7-9b56-254415f67890" + }, + "required": false, + "description": "Filter schedules by the owner's user ID. Use the List users endpoint to retrieve user IDs.", + "name": "ownerId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Search term for filtering schedules by name, dashboard name, or owner name (case-insensitive).", + "example": "Weekly" + }, + "required": false, + "description": "Search term for filtering schedules by name, dashboard name, or owner name (case-insensitive).", + "name": "q", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "alert", + "schedule" + ], + "description": "Filter by type: alert, schedule.", + "example": "schedule" + }, + "required": false, + "description": "Filter by type: alert, schedule.", + "name": "scheduleType", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "success", + "error", + "canceled", + "none" + ], + "description": "Filter schedules by delivery status: success, error, canceled, none.", + "example": "success" + }, + "required": false, + "description": "Filter schedules by delivery status: success, error, canceled, none.", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of schedules", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SchedulesListItem" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + } + } + }, + "post": { + "description": "Create a new scheduled delivery for a dashboard. Required fields vary by destinationType (email, webhook, sftp, slack). For org API keys, use the userId query parameter to create the schedule on behalf of a specific user.", + "operationId": "schedulesCreate", + "summary": "Create schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Membership ID of the user who should own the schedule (org API keys only). If not provided, the schedule is owned by the API key owner. User-scoped API keys cannot use this parameter.", + "example": "987fcdeb-51a2-43d7-9b56-254415f67890" + }, + "required": false, + "description": "Membership ID of the user who should own the schedule (org API keys only). If not provided, the schedule is owned by the API key owner. User-scoped API keys cannot use this parameter.", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "bucketName": { + "type": "string", + "description": "S3 bucket name (S3 destination only). Must be 3-63 characters, lowercase.", + "example": "my-reports-bucket" + }, + "conditionQueryMapKey": { + "type": "string", + "description": "The ID of the query to monitor for triggering an alert. Required if conditionType is provided.", + "example": "Jmn2r3KV" + }, + "conditionType": { + "type": "string", + "enum": [ + "RESULTS_CHANGED", + "RESULTS_UNCHANGED", + "RESULTS_PRESENT", + "RESULTS_MISSING" + ], + "description": "Defines the type of condition to use for alerts. Required if conditionQueryMapKey is provided.", + "example": "RESULTS_PRESENT" + }, + "destinationType": { + "type": "string", + "enum": [ + "email", + "webhook", + "sftp", + "slack", + "s3" + ], + "description": "The delivery destination type", + "example": "email" + }, + "enableFormatting": { + "type": "boolean", + "description": "If true, formatting will be enabled in the output", + "example": false + }, + "fanOut": { + "type": "boolean", + "description": "If true, send personalized emails to each recipient (email only)", + "example": false + }, + "filterConfig": { + "description": "Filter conditions to apply to the task", + "example": { + "status": [ + "active", + "pending" + ] + } + }, + "format": { + "type": "string", + "enum": [ + "link_only", + "pdf", + "png", + "csv", + "xlsx", + "json" + ], + "description": "The output format: link_only, pdf, png, csv, xlsx, json", + "example": "pdf" + }, + "hideHiddenFields": { + "type": "boolean", + "description": "If true, hidden fields won't be displayed (csv/xlsx only)", + "example": false + }, + "hideTitle": { + "type": "boolean", + "description": "If true, hide the title in output (pdf/png only)", + "example": false + }, + "identifier": { + "type": "string", + "description": "The ID of the dashboard to schedule", + "example": "12db1a0a" + }, + "keyPrefix": { + "type": "string", + "description": "S3 key prefix / folder path (S3 destination only). Leading slashes are normalized.", + "example": "reports/weekly/" + }, + "killJobsOnFailure": { + "type": "boolean", + "description": "If true, stop entire job if any queries fail", + "example": false + }, + "name": { + "type": "string", + "description": "The name of the scheduled task", + "example": "Weekly Sales Report" + }, + "recipients": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Recipient email address", + "example": "user@example.com" + } + }, + "required": [ + "email" + ] + }, + "description": "Email recipients (email destination only). For Slack destinations, use the \"recipients\" field with a channel ID string or user ID(s) as a string or array." + }, + "region": { + "type": "string", + "description": "AWS region where the S3 bucket is located (S3 destination only).", + "example": "us-east-1" + }, + "roleArn": { + "type": "string", + "description": "ARN of the cross-account IAM role Omni will assume to write to the S3 bucket (S3 destination only).", + "example": "arn:aws:iam::123456789012:role/OmniS3DeliveryRole" + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", + "example": "0 9 ? * MON *" + }, + "showContentLink": { + "type": "boolean", + "description": "If true, include a link to the content", + "example": true + }, + "showFilters": { + "type": "boolean", + "description": "If true, show applied filters in output", + "example": true + }, + "slackRecipientType": { + "type": "string", + "description": "Slack recipient type (Slack destination only). Use \"channel\" to deliver to a single Slack channel, or \"users\" to deliver to one or more Slack users via direct message.", + "example": "channel" + }, + "testNow": { + "type": "boolean", + "description": "If true, run immediately instead of scheduling", + "example": false + }, + "timezone": { + "type": "string", + "description": "IANA timezone for the schedule", + "example": "America/New_York" + }, + "timezoneOverride": { + "type": [ + "string", + "null" + ], + "description": "Optional IANA timezone applied to query execution at render time. Distinct from `timezone` (which controls *when* the schedule fires). Omit or pass null for no override.", + "example": "Europe/Paris" + }, + "webhookUrl": { + "type": "string", + "format": "uri", + "description": "Webhook URL (webhook destination only)", + "example": "https://example.com/webhook" + } + }, + "required": [ + "destinationType", + "format", + "identifier", + "name", + "schedule", + "timezone" + ], + "description": "Request body for creating a scheduled task. Required fields vary by destinationType.", + "title": "SchedulesCreateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Schedule created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "delivererRoleArn": { + "type": "string", + "description": "The ARN of the Omni deliverer role. Use this as the Principal in your IAM role trust policy. Only returned for S3 destinations.", + "example": "arn:aws:iam::529831494235:role/OmniSchedulerDelivererRole" + }, + "externalId": { + "type": "string", + "format": "uuid", + "description": "The organization ID used as the external ID for confused deputy prevention. Add this to your IAM role trust policy as the sts:ExternalId condition. Static across all S3 destinations for your organization. Only returned for S3 destinations.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Created schedule ID (only when testNow is false)", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "message": { + "type": "string", + "description": "Success message", + "example": "Successfully created schedule" + } + }, + "required": [ + "message" + ], + "description": "Create schedule response", + "title": "SchedulesCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or filter configuration" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - cannot schedule this dashboard" + }, + "404": { + "description": "Dashboard not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}": { + "get": { + "operationId": "schedulesGet", + "summary": "Get schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Membership ID of the user whose access should be checked (org API keys only). When provided, the endpoint checks if that user has permission to view the schedule. User-scoped API keys cannot use this parameter.", + "example": "987fcdeb-51a2-43d7-9b56-254415f67890" + }, + "required": false, + "description": "Membership ID of the user whose access should be checked (org API keys only). When provided, the endpoint checks if that user has permission to view the schedule. User-scoped API keys cannot use this parameter.", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Schedule details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - must be schedule owner or have manage permission" + }, + "404": { + "description": "Schedule not found" + } + } + }, + "put": { + "operationId": "schedulesUpdate", + "summary": "Update schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schedule updated successfully" + }, + "400": { + "description": "Invalid request body or filter configuration" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - must be schedule owner or have manage permission" + }, + "404": { + "description": "Schedule or dashboard not found" + } + } + }, + "delete": { + "operationId": "schedulesDelete", + "summary": "Delete schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schedule deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - must be schedule owner or have manage permission" + }, + "404": { + "description": "Schedule not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/recipients": { + "get": { + "operationId": "schedulesRecipientsGet", + "summary": "Get schedule recipients", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schedule recipients", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesRecipientsGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Schedule not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/add-recipients": { + "put": { + "operationId": "schedulesAddRecipients", + "summary": "Add schedule recipients", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesAddRecipientsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Recipients added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesAddRecipientsResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - at least one email, userId, or userGroupId required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Schedule not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/remove-recipients": { + "put": { + "operationId": "schedulesRemoveRecipients", + "summary": "Remove schedule recipients", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesRemoveRecipientsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Recipients removed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesRemoveRecipientsResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - at least one email, userId, or userGroupId required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Schedule not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/pause": { + "put": { + "operationId": "schedulesPause", + "summary": "Pause schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schedule paused successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Schedule not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/resume": { + "put": { + "operationId": "schedulesResume", + "summary": "Resume schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schedule resumed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Schedule not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/trigger": { + "post": { + "operationId": "schedulesTrigger", + "summary": "Trigger schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schedule triggered successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Schedule not found" + }, + "409": { + "description": "Schedule cannot be triggered (paused, system-disabled, or another execution is in progress)" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/transfer-ownership": { + "put": { + "operationId": "schedulesTransferOwnership", + "summary": "Transfer schedule ownership", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesTransferOwnershipBody" + } + } + } + }, + "responses": { + "200": { + "description": "Ownership transferred successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid user ID" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - must be schedule owner or have manage permission" + }, + "404": { + "description": "Schedule or user not found" + } + } + } + }, + "/api/scim/v2/Users": { + "get": { + "operationId": "scimUsersList", + "summary": "List SCIM users", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "pattern": "^-?\\d*\\.?\\d+$", + "default": 100, + "description": "Maximum number of results to return", + "example": 100 + }, + "required": false, + "description": "Maximum number of results to return", + "name": "count", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "SCIM filter expression", + "example": "userName eq \"user@example.com\"" + }, + "required": false, + "description": "SCIM filter expression", + "name": "filter", + "in": "query" + }, + { + "schema": { + "type": "string", + "pattern": "^-?\\d*\\.?\\d+$", + "default": 1, + "description": "Index of the first result to return (1-based)", + "example": 1 + }, + "required": false, + "description": "Index of the first result to return (1-based)", + "name": "startIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of SCIM users", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUsersListResponse" + } + } + } + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + } + } + }, + "post": { + "operationId": "scimUsersCreate", + "summary": "Create SCIM user", + "tags": [ + "SCIM" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "SCIM user created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "409": { + "description": "User with this email already exists" + } + } + } + }, + "/api/scim/v2/Users/{id}": { + "get": { + "operationId": "scimUsersGet", + "summary": "Get SCIM user", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "SCIM user ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "SCIM user details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserResponse" + } + } + } + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "User not found" + } + } + }, + "put": { + "operationId": "scimUsersReplace", + "summary": "Replace SCIM user", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "SCIM user ID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserPutRequest" + } + } + } + }, + "responses": { + "200": { + "description": "SCIM user replaced", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "User not found" + } + } + }, + "patch": { + "operationId": "scimUsersUpdate", + "summary": "Update SCIM user", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "SCIM user ID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserPatchRequest" + } + } + } + }, + "responses": { + "200": { + "description": "SCIM user updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserResponse" + } + } + } + }, + "400": { + "description": "Invalid patch operations" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "User not found" + } + } + }, + "delete": { + "operationId": "scimUsersDelete", + "summary": "Delete SCIM user", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "SCIM user ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "204": { + "description": "SCIM user deleted" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "User not found" + } + } + } + }, + "/api/scim/v2/embed/Users": { + "get": { + "description": "List embed users. Embed users are externally-managed users created via the embed SSO flow.", + "operationId": "scimEmbedUsersList", + "summary": "List embed users", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "pattern": "^-?\\d*\\.?\\d+$", + "default": 100, + "description": "Maximum number of results to return", + "example": 100 + }, + "required": false, + "description": "Maximum number of results to return", + "name": "count", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "SCIM filter expression", + "example": "userName eq \"user@example.com\"" + }, + "required": false, + "description": "SCIM filter expression", + "name": "filter", + "in": "query" + }, + { + "schema": { + "type": "string", + "pattern": "^-?\\d*\\.?\\d+$", + "default": 1, + "description": "Index of the first result to return (1-based)", + "example": 1 + }, + "required": false, + "description": "Index of the first result to return (1-based)", + "name": "startIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of embed users", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUsersListResponse" + } + } + } + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + } + } + } + }, + "/api/scim/v2/embed/Users/{id}": { + "get": { + "description": "Get details for a specific embed user.", + "operationId": "scimEmbedUsersGet", + "summary": "Get embed user", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "SCIM user ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Embed user details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserResponse" + } + } + } + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "Embed user not found" + } + } + }, + "delete": { + "description": "Permanently delete an embed user. Unlike standard SCIM user deletion which soft-deletes, this performs a hard delete.", + "operationId": "scimEmbedUsersDelete", + "summary": "Delete embed user", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "SCIM user ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "204": { + "description": "Embed user permanently deleted" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "Embed user not found" + } + } + } + }, + "/api/scim/v2/Groups": { + "get": { + "operationId": "scimGroupsList", + "summary": "List SCIM groups", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "pattern": "^-?\\d*\\.?\\d+$", + "default": 100, + "description": "Maximum number of results to return", + "example": 100 + }, + "required": false, + "description": "Maximum number of results to return", + "name": "count", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "members" + ], + "description": "Attributes to exclude from the response", + "example": "members" + }, + "required": false, + "description": "Attributes to exclude from the response", + "name": "excludedAttributes", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "SCIM filter expression", + "example": "displayName eq \"Engineering\"" + }, + "required": false, + "description": "SCIM filter expression", + "name": "filter", + "in": "query" + }, + { + "schema": { + "type": "string", + "pattern": "^-?\\d*\\.?\\d+$", + "default": 1, + "description": "Index of the first result to return (1-based)", + "example": 1 + }, + "required": false, + "description": "Index of the first result to return (1-based)", + "name": "startIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of SCIM groups", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + } + } + }, + "post": { + "operationId": "scimGroupsCreate", + "summary": "Create SCIM group", + "tags": [ + "SCIM" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "SCIM group created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "409": { + "description": "Group with this name already exists" + } + } + } + }, + "/api/scim/v2/Groups/{miniUuid}": { + "get": { + "operationId": "scimGroupsGet", + "summary": "Get SCIM group", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "required": true, + "description": "Short identifier of the group", + "name": "miniUuid", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "members" + ], + "description": "Attributes to exclude from the response", + "example": "members" + }, + "required": false, + "description": "Attributes to exclude from the response", + "name": "excludedAttributes", + "in": "query" + } + ], + "responses": { + "200": { + "description": "SCIM group details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupResponse" + } + } + } + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "Group not found" + } + } + }, + "put": { + "operationId": "scimGroupsReplace", + "summary": "Replace SCIM group", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "required": true, + "description": "Short identifier of the group", + "name": "miniUuid", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupsReplaceBody" + } + } + } + }, + "responses": { + "200": { + "description": "SCIM group replaced", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "Group not found" + } + } + }, + "patch": { + "operationId": "scimGroupsUpdate", + "summary": "Update SCIM group", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "required": true, + "description": "Short identifier of the group", + "name": "miniUuid", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupsPatchBody" + } + } + } + }, + "responses": { + "200": { + "description": "SCIM group updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupResponse" + } + } + } + }, + "400": { + "description": "Invalid patch operations" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "Group not found" + } + } + }, + "delete": { + "operationId": "scimGroupsDelete", + "summary": "Delete SCIM group", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "required": true, + "description": "Short identifier of the group", + "name": "miniUuid", + "in": "path" + } + ], + "responses": { + "204": { + "description": "SCIM group deleted" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "Group not found" + } + } + } + }, + "/api/unstable/documents/{identifier}/export": { + "get": { + "operationId": "unstableDocumentsExport", + "summary": "Export document (unstable)", + "tags": [ + "Unstable" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (miniUuid or full UUID)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (miniUuid or full UUID)", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Document export data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentExportResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/unstable/documents/import": { + "post": { + "operationId": "unstableDocumentsImport", + "summary": "Import document (unstable)", + "tags": [ + "Unstable" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentImportBody" + } + } + } + }, + "responses": { + "201": { + "description": "Document imported successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentImportResponse" + } + } + } + }, + "400": { + "description": "Invalid export data" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Base model not found" + } + } + } + }, + "/api/v1/user-attributes": { + "get": { + "description": "Returns all user attribute definitions in the organization, including system-defined attributes (e.g. omni_user_id, omni_user_email) and custom attributes.", + "operationId": "userAttributesList", + "summary": "List all user attribute definitions", + "tags": [ + "User Attributes" + ], + "responses": { + "200": { + "description": "List of all user attribute definitions in the organization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserAttributesListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" + } + } + } + }, + "/api/v1/uploads": { + "get": { + "operationId": "uploadsList", + "summary": "List uploads", + "tags": [ + "Uploads" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction (default: desc)", + "example": "desc" + }, + "required": false, + "description": "Sort direction (default: desc)", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "createdAt", + "fileName", + "updatedAt" + ], + "default": "updatedAt", + "description": "Field to sort by (default: updatedAt)" + }, + "required": false, + "description": "Field to sort by (default: updatedAt)", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by connection ID" + }, + "required": false, + "description": "Filter by connection ID", + "name": "connectionId", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by model ID. Shared models return connection uploads; workbook models return their own uploads." + }, + "required": false, + "description": "Filter by model ID. Shared models return connection uploads; workbook models return their own uploads.", + "name": "modelId", + "in": "query" + }, + { + "schema": { + "type": "string", + "maxLength": 256, + "description": "Search term to filter by file name" + }, + "required": false, + "description": "Search term to filter by file name", + "name": "searchTerm", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "csv", + "spreadsheet" + ], + "default": "csv", + "description": "Filter by upload type (default: csv)" + }, + "required": false, + "description": "Filter by upload type (default: csv)", + "name": "type", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of uploads with metadata", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadsListResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found (when modelId is provided)" + } + } + }, + "post": { + "operationId": "uploadsCreate", + "summary": "Upload CSV file", + "tags": [ + "Uploads" + ], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/UploadCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "CSV uploaded successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request (missing fields, invalid file type, or CSV parsing failed)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or branch not found" + } + } + } + }, + "/api/v1/uploads/{uploadId}": { + "delete": { + "operationId": "uploadsDelete", + "summary": "Delete an upload", + "tags": [ + "Uploads" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "ID of the upload to delete" + }, + "required": true, + "description": "ID of the upload to delete", + "name": "uploadId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Upload deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadDeleteResponse" + } + } + } + }, + "400": { + "description": "Invalid upload ID format" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Upload not found or already deleted" + } + } + } + }, + "/api/v1/users/{id}/model-roles": { + "get": { + "operationId": "usersGetModelRoles", + "summary": "Get user model roles", + "tags": [ + "Users" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "User membership ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter results to a specific connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": false, + "description": "Filter results to a specific connection", + "name": "connectionId", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter results to a specific model", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": false, + "description": "Filter results to a specific model", + "name": "modelId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "User model role assignments", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersGetModelRolesResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "User not found" + } + } + }, + "post": { + "operationId": "usersAssignModelRole", + "summary": "Assign model role to user", + "tags": [ + "Users" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "User membership ID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersAssignModelRoleBody" + } + } + } + }, + "responses": { + "200": { + "description": "Role assigned successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersAssignModelRoleResponse" + } + } + } + }, + "400": { + "description": "Invalid request - connectionId or modelId required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "User, model, or connection not found" + } + } + } + }, + "/api/v1/users/email-only": { + "get": { + "operationId": "usersListEmailOnly", + "summary": "List email-only users", + "tags": [ + "Users" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination" + }, + "required": false, + "description": "Cursor for pagination", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by email address", + "example": "user@example.com" + }, + "required": false, + "description": "Filter by email address", + "name": "email", + "in": "query" + }, + { + "schema": { + "type": "number", + "minimum": 1, + "maximum": 20, + "default": 20, + "description": "Number of results per page (max 20)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (max 20)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of email-only users", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersListEmailOnlyResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + }, + "post": { + "operationId": "usersCreateEmailOnly", + "summary": "Create or update email-only user", + "tags": [ + "Users" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersCreateEmailOnlyBody" + } + } + } + }, + "responses": { + "200": { + "description": "Email-only user created or updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersCreateEmailOnlyResponse" + } + } + } + }, + "400": { + "description": "Invalid email address or failed to create user" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + } + }, + "/api/v1/users/email-only/bulk": { + "post": { + "operationId": "usersCreateEmailOnlyBulk", + "summary": "Create email-only users in bulk", + "tags": [ + "Users" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersCreateEmailOnlyBulkBody" + } + } + } + }, + "responses": { + "201": { + "description": "Email-only users created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersCreateEmailOnlyBulkResponse" + } + } + } + }, + "400": { + "description": "Invalid request - must provide 1-20 users with valid emails" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + } + }, + "/api/v1/user-groups/{id}/model-roles": { + "get": { + "operationId": "userGroupsGetModelRoles", + "summary": "Get user group model roles", + "tags": [ + "Users" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "User group short identifier (miniUuid)", + "example": "abc123" + }, + "required": true, + "description": "User group short identifier (miniUuid)", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter results to a specific connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": false, + "description": "Filter results to a specific connection", + "name": "connectionId", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter results to a specific model", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": false, + "description": "Filter results to a specific model", + "name": "modelId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "User group model role assignments", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserGroupsGetModelRolesResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "User group not found" + } + } + }, + "post": { + "operationId": "userGroupsAssignModelRole", + "summary": "Assign model role to user group", + "tags": [ + "Users" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "User group short identifier (miniUuid)", + "example": "abc123" + }, + "required": true, + "description": "User group short identifier (miniUuid)", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserGroupsAssignModelRoleBody" + } + } + } + }, + "responses": { + "200": { + "description": "Role assigned successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserGroupsAssignModelRoleResponse" + } + } + } + }, + "400": { + "description": "Invalid request - connectionId or modelId required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "User group, model, or connection not found" + } + } + } + }, + "/api/v1/whoami": { + "get": { + "description": "Returns the authenticated caller's own identity, API key scope, organization role, and resolved per-model permissions. Self-scoped and available to non-admins: it lets a caller decide whether an action is permitted without attempting it. Pass `modelId` to scope `rolesByModel` to specific models.", + "operationId": "whoami", + "summary": "Get current identity and permissions (whoami)", + "tags": [ + "Whoami" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Optional model filter. A single model id or a comma-separated list. When provided, `rolesByModel` contains only these models. When omitted, models the caller can access are returned (up to a limit; see `rolesByModelTruncated`).", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": false, + "description": "Optional model filter. A single model id or a comma-separated list. When provided, `rolesByModel` contains only these models. When omitted, models the caller can access are returned (up to a limit; see `rolesByModelTruncated`).", + "name": "modelId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Caller's identity, key scope, org role, and per-model permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WhoamiResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "One or more requested `modelId`s do not exist or are not accessible to the caller" + } + } + } + } + }, + "webhooks": {} +} \ No newline at end of file diff --git a/spec/openapi.processed.json b/spec/openapi.processed.json new file mode 100644 index 0000000..57c4d92 --- /dev/null +++ b/spec/openapi.processed.json @@ -0,0 +1,25769 @@ +{ + "info": { + "description": "The Omni API enables programmatic access to dashboards, documents, models, and other resources.", + "title": "Omni API", + "version": "1.0.0" + }, + "openapi": "3.1.0", + "security": [ + { + "bearerAuth": [] + } + ], + "tags": [ + { + "description": "AI-powered data analysis. Submit natural language questions as synchronous queries or asynchronous jobs, and retrieve results including generated queries, data, and summarized answers.", + "name": "AI" + }, + { + "description": "Saved AI prompts that fire on a schedule and deliver the response to email recipients.", + "name": "AI Routines" + }, + { + "description": "AI evaluation: manage prompt sets and runs used to score AI quality against curated prompt suites.", + "name": "AI Eval" + }, + { + "description": "AI-generated model suggestions: list, generate, schedule, and manage suggested improvements to a shared model.", + "name": "AI Model Suggestions" + }, + { + "description": "API token management", + "name": "API Tokens" + }, + { + "description": "Database connections and environments", + "name": "Connections" + }, + { + "description": "Content retrieval", + "name": "Content" + }, + { + "description": "Dashboard downloads and filters", + "name": "Dashboards" + }, + { + "description": "Document and workbook management", + "name": "Documents" + }, + { + "description": "Embedded SSO session management", + "name": "Embed" + }, + { + "description": "Folder organization and permissions", + "name": "Folders" + }, + { + "description": "Label management", + "name": "Labels" + }, + { + "description": "Semantic model management", + "name": "Models" + }, + { + "description": "Query execution", + "name": "Query" + }, + { + "description": "Schedule management and delivery", + "name": "Schedules" + }, + { + "description": "SCIM provisioning", + "name": "SCIM" + }, + { + "description": "Unstable API routes - subject to change", + "name": "Unstable" + }, + { + "description": "File upload management", + "name": "Uploads" + }, + { + "description": "User attribute definitions management", + "name": "User Attributes" + }, + { + "description": "User and group management", + "name": "Users" + }, + { + "description": "Self-introspection: the authenticated caller can discover their own identity, key scope, org role, and resolved per-model permissions.", + "name": "Whoami" + } + ], + "components": { + "securitySchemes": { + "bearerAuth": { + "bearerFormat": "API Token", + "description": "Include in the Authorization header as: Authorization: Bearer ", + "scheme": "bearer", + "type": "http" + } + }, + "schemas": { + "DbtEnvironmentVariableUpdate": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Existing variable ID" + }, + "isSecret": { + "type": "boolean", + "description": "Whether the variable value is secret" + }, + "value": { + "type": [ + "string", + "null" + ], + "description": "Updated variable value. Omit or set to null to keep the existing value for secret variables." + } + }, + "required": [ + "id", + "isSecret" + ], + "additionalProperties": false, + "description": "Update an existing variable by ID. Variable names cannot be changed after creation.", + "title": "DbtEnvironmentVariableUpdate" + }, + "CompositeFilter": { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + } + }, + "required": [ + "kind", + "type", + "values" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + } + }, + "required": [ + "kind", + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + } + }, + "required": [ + "type", + "user_attribute_name" + ] + }, + { + "$ref": "#/components/schemas/CompositeFilter" + } + ] + }, + "description": "Child filters \u2014 each a simple filter or another composite filter. Recursive; see the dashboard-filters reference for the full grammar." + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + } + }, + "required": [ + "conjunction", + "filters", + "type" + ] + }, + "AiGenerateQueryResponse": { + "type": "object", + "properties": { + "baseView": { + "type": [ + "string", + "null" + ], + "description": "The base view name used for query generation when queryAllViews surfaced a non-topic view. Mutually exclusive with `topic` \u2014 exactly one is non-null when a query was generated.", + "example": null + }, + "downgradedModelTier": { + "type": "string", + "description": "Present only when the organization is over its AI downgrade threshold, signaling the query was generated on a downgraded (cheaper) model tier (e.g. 'haiku') to conserve credits. Advisory and best-effort \u2014 the call still succeeds, and clients may surface that a downgraded model was used. Absent when no downgrade applied.", + "example": "haiku" + }, + "error": { + "type": [ + "object", + "null" + ], + "properties": { + "detail": { + "type": "string", + "description": "Detailed error message explaining why query generation failed.", + "example": "The AI was unable to generate a query for this prompt. Try rephrasing your question to be more specific about the data you want to retrieve." + }, + "message": { + "type": "string", + "description": "Short error summary.", + "example": "No query generated" + } + }, + "required": [ + "detail", + "message" + ], + "description": "Error details if query generation failed. Null on success." + }, + "query": { + "$ref": "#/components/schemas/AiSemanticQuery" + }, + "result": { + "type": "object", + "additionalProperties": {}, + "description": "Query execution results as a JSON object. Only present when runQuery is true (the default) and the query executed successfully. The structure contains the query result data." + }, + "topic": { + "type": [ + "string", + "null" + ], + "description": "The topic name used for query generation. Mutually exclusive with `baseView` \u2014 exactly one is non-null when a query was generated.", + "example": "order_items" + }, + "workbookUrl": { + "type": "string", + "format": "uri", + "description": "URL to view and edit the generated query in an Omni workbook. Only present when workbookUrl was set to true in the request.", + "example": "https://myorg.omni.co/w/abc123/1" + } + }, + "required": [ + "error", + "query" + ] + }, + "AiSemanticQuery": { + "type": "object", + "additionalProperties": true, + "description": "The generated semantic query definition. Null if generation failed. This query can be passed directly to the POST /api/v1/query/run endpoint. (Not statically modeled; use plain dicts.)" + }, + "AiQuerySort": { + "type": "object", + "properties": { + "column_name": { + "type": "string", + "description": "Fully qualified field name to sort by (e.g., \"view_name.field_name\").", + "example": "order_items.total_revenue" + }, + "sort_descending": { + "type": "boolean", + "description": "Whether to sort in descending order.", + "example": true + } + }, + "required": [ + "column_name", + "sort_descending" + ] + }, + "ApiError400": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Bad Request: prompt: Required" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 400 + } + }, + "required": [ + "detail", + "status" + ] + }, + "ApiError401": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Unauthorized: Missing or invalid API key" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 401 + } + }, + "required": [ + "detail", + "status" + ] + }, + "AiCreditShutoffError": { + "type": "object", + "properties": { + "code": { + "type": "string", + "enum": [ + "shutoff" + ], + "description": "Stable reason code identifying an AI-credit shutoff.", + "example": "shutoff" + }, + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "The AI credit limit has been reached. Contact your administrator for assistance." + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 402 + } + }, + "required": [ + "code", + "detail", + "status" + ] + }, + "ApiError403": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Forbidden: AI query generation is not enabled for this organization" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 403 + } + }, + "required": [ + "detail", + "status" + ] + }, + "ApiError404": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Model 770e8400-e29b-41d4-a716-446655440002 not found" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 404 + } + }, + "required": [ + "detail", + "status" + ] + }, + "AiGenerateQueryBody": { + "allOf": [ + { + "$ref": "#/components/schemas/AiTopicParams" + }, + { + "type": "object", + "properties": { + "prompt": { + "type": "string", + "description": "The natural language prompt describing the data you want to retrieve.", + "example": "Show me total revenue by month for the last year" + }, + "queryAllViews": { + "type": "boolean", + "description": "If true and the model has query_all_views_and_fields enabled, AI can query views not in any topic." + }, + "runQuery": { + "type": "boolean", + "description": "Whether to execute the generated query and return results. Defaults to true. Set to false to only generate the query definition without executing it.", + "example": true + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID to execute the query as. Their permissions will be applied for row-level security. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", + "example": "990e8400-e29b-41d4-a716-446655440004" + }, + "workbookUrl": { + "type": "boolean", + "description": "If true, creates a new workbook with the generated query and returns its URL. Useful for sharing results or further exploration.", + "example": false + } + }, + "required": [ + "prompt" + ] + } + ] + }, + "AiTopicParams": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "currentTopicName": { + "type": "string", + "description": "The name of the current topic to scope query generation. If not provided, AI will automatically select the best topic for your prompt.", + "example": "order_items" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The UUID of the shared model to query against. Only shared models are supported.", + "example": "770e8400-e29b-41d4-a716-446655440002" + } + }, + "required": [ + "modelId" + ] + }, + "AiPickTopicResponse": { + "type": "object", + "properties": { + "topicId": { + "type": "string", + "description": "The name of the topic that best matches the prompt. Use this as the topicName parameter when calling generate-query or submitting an AI job.", + "example": "order_items" + } + }, + "required": [ + "topicId" + ] + }, + "AiPickTopicBody": { + "allOf": [ + { + "$ref": "#/components/schemas/AiTopicParams" + }, + { + "type": "object", + "properties": { + "potentialTopicNames": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional list of topic names to limit consideration to. If not provided, all topics the user has access to in the model will be evaluated.", + "example": [ + "order_items", + "customers", + "products" + ] + }, + "prompt": { + "type": "string", + "description": "The natural language prompt to analyze. The AI will determine which topic best matches the data described in this prompt.", + "example": "How many orders were placed last month?" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID to evaluate topic access as. Their permissions will be used for permission-aware topic selection. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", + "example": "990e8400-e29b-41d4-a716-446655440004" + } + }, + "required": [ + "prompt" + ] + } + ] + }, + "AiSearchOmniDocsResponse": { + "type": "object", + "properties": { + "answer": { + "type": "string", + "description": "A synthesized answer to the question, based on the Omni documentation.", + "example": "To create a dashboard filter, navigate to your dashboard and click the \"Add Filter\" button..." + }, + "sources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "The title of the source documentation page.", + "example": "Dashboard Filters" + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL of the source documentation page.", + "example": "https://docs.omni.co/docs/dashboards/filters" + } + }, + "required": [ + "title", + "url" + ] + }, + "description": "List of documentation pages that were used to synthesize the answer." + } + }, + "required": [ + "answer", + "sources" + ] + }, + "AiSearchOmniDocsBody": { + "type": "object", + "properties": { + "question": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "description": "A natural language question about Omni features, configuration, modeling, dashboards, or other topics covered in the Omni documentation.", + "example": "How do I create a dashboard filter?" + } + }, + "required": [ + "question" + ] + }, + "AiJobSubmitResponse": { + "type": "object", + "properties": { + "conversationId": { + "type": "string", + "format": "uuid", + "description": "The conversation ID for this job. Pass this as conversationId in subsequent job submissions to continue the conversation with additional context.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "jobId": { + "type": "string", + "format": "uuid", + "description": "The unique identifier for the created job. Use this to poll status via GET /api/v1/ai/jobs/{jobId} or retrieve results via GET /api/v1/ai/jobs/{jobId}/result.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "omniChatUrl": { + "type": "string", + "format": "uri", + "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" + } + }, + "required": [ + "conversationId", + "jobId", + "omniChatUrl" + ] + }, + "ApiError409": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "An active job already exists for this conversation" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 409 + } + }, + "required": [ + "detail", + "status" + ] + }, + "AiJobSubmitBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId. Use this to query against in-progress model changes.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "conversationId": { + "type": "string", + "format": "uuid", + "description": "Conversation ID to continue an existing conversation thread. The AI will have access to the context from previous jobs in the same conversation. If omitted, a new conversation is created. Only one active job can exist per conversation.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The UUID of the model to query against. Must be a shared model, or a shared-extension model usable as a workbook base.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "progressWebhookEnabled": { + "type": "boolean", + "default": false, + "description": "When true, real-time progress events are POSTed to webhookUrl during execution (e.g., \"Searching for revenue fields\", \"Query returned 42 rows\"). Requires webhookUrl. Progress events are best-effort: single attempt, no retries, failures do not affect job execution.", + "example": true + }, + "prompt": { + "type": "string", + "minLength": 1, + "description": "The natural language prompt for the AI to process. The AI will analyze your question, generate appropriate queries, execute them, and return a summarized answer.", + "example": "What are the top 5 products by revenue this quarter?" + }, + "topicName": { + "type": "string", + "maxLength": 256, + "description": "Topic name to scope query generation. Topics define a set of related views and their join paths. If not provided, the AI will automatically select the best topic. Use the pick-topic endpoint to determine the right topic programmatically.", + "example": "order_items" + }, + "webhookMetadata": { + "type": "object", + "additionalProperties": {}, + "description": "Arbitrary metadata object that will be included unchanged in webhook payloads. Use this to correlate webhook notifications with your own system (e.g., tracking IDs, channel references).", + "example": { + "externalId": "task-123", + "slackChannel": "C0123456789" + } + }, + "webhookSigningSecret": { + "type": "string", + "description": "Secret key for HMAC-SHA256 webhook payload signing. When provided, each webhook request includes X-Omni-Signature and X-Omni-Signature-Timestamp headers for verification. Required if webhookUrl is specified." + }, + "webhookUrl": { + "type": "string", + "format": "uri", + "description": "URL to receive webhook POSTs. Always receives a terminal event (job.complete, job.failed, or job.denied) when the job finishes; a job.denied event (e.g. the organization is over its AI credit limit) additionally carries a reason field. When progressWebhookEnabled is true, also receives real-time progress events during execution.", + "example": "https://example.com/webhooks/omni" + } + }, + "required": [ + "modelId", + "prompt" + ] + }, + "AiJobStatusResponse": { + "type": "object", + "properties": { + "branchId": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Branch ID used for model context, or null if querying the main shared model." + }, + "cancelledAt": { + "type": "string", + "format": "date-time", + "description": "When the job was cancelled. Only present in CANCELLED state.", + "example": "2025-01-15T10:00:12.000Z" + }, + "cancelledBy": { + "type": "string", + "format": "uuid", + "description": "User ID of who cancelled the job. Only present in CANCELLED state.", + "example": "990e8400-e29b-41d4-a716-446655440004" + }, + "completedAt": { + "type": "string", + "format": "date-time", + "description": "When the job finished (successfully or with error). Present in COMPLETE and FAILED states.", + "example": "2025-01-15T10:01:30.000Z" + }, + "conversationId": { + "type": "string", + "format": "uuid", + "description": "The conversation this job belongs to. Use this to submit follow-up jobs in the same conversation thread.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When the job was submitted.", + "example": "2025-01-15T10:00:00.000Z" + }, + "error": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Machine-readable error code.", + "example": "QUERY_EXECUTION_ERROR" + }, + "detail": { + "type": "string", + "description": "Additional error detail or context.", + "example": "The query timed out after 300 seconds" + }, + "message": { + "type": "string", + "description": "Human-readable error message.", + "example": "Column 'revenue' not found in table 'orders'" + } + }, + "required": [ + "message" + ], + "additionalProperties": {}, + "description": "Error details explaining why the job failed. Only present in FAILED state." + }, + "executionStartedAt": { + "type": "string", + "format": "date-time", + "description": "When execution began. Present once the job transitions from QUEUED to EXECUTING. May be absent on jobs that failed or were cancelled before execution started.", + "example": "2025-01-15T10:00:05.000Z" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique identifier for this job.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "modelId": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "The shared model ID used for query generation.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "omniChatUrl": { + "type": "string", + "format": "uri", + "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" + }, + "organizationId": { + "type": "string", + "format": "uuid", + "description": "The organization that owns this job.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "progress": { + "type": [ + "object", + "null" + ], + "properties": { + "iteration": { + "type": "integer", + "description": "Current iteration number. The AI may take multiple iterations to refine queries and generate a complete answer.", + "example": 2 + }, + "message": { + "type": "string", + "description": "Human-readable status message describing what the AI is currently doing.", + "example": "Running query: Top products by revenue" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When this progress update was recorded.", + "example": "2025-01-15T10:00:08.000Z" + } + }, + "required": [ + "iteration", + "message", + "updatedAt" + ], + "description": "Real-time progress information. Only present in EXECUTING state. Null if no progress has been reported yet. Updated in real-time as the AI works through iterations." + }, + "prompt": { + "type": "string", + "description": "The natural language prompt that was submitted.", + "example": "What are the top 5 products by revenue?" + }, + "resultSummary": { + "type": "string", + "description": "Markdown-formatted summary of the job result. Only present in COMPLETE state. For the full result with query details and data, use GET /api/v1/ai/jobs/{jobId}/result.", + "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + }, + "state": { + "type": "string", + "enum": [ + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED" + ], + "description": "Current state of the job. Terminal states are COMPLETE, FAILED, and CANCELLED. Poll until the job reaches a terminal state.", + "example": "QUEUED" + }, + "topicName": { + "type": [ + "string", + "null" + ], + "description": "Topic name used to scope query generation, or null if the AI selected the topic automatically.", + "example": "order_items" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When the job record was last modified.", + "example": "2025-01-15T10:00:05.000Z" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "The user ID who created (or is associated with) this job.", + "example": "990e8400-e29b-41d4-a716-446655440004" + } + }, + "required": [ + "branchId", + "conversationId", + "createdAt", + "id", + "modelId", + "omniChatUrl", + "organizationId", + "prompt", + "state", + "topicName", + "updatedAt", + "userId" + ] + }, + "AiJobCancelResponse": { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "format": "uuid", + "description": "The job ID that was requested to cancel.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "state": { + "type": "string", + "enum": [ + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED" + ], + "description": "The job state after the cancellation attempt. CANCELLED if the cancellation was successful. If the job was already in a terminal state (COMPLETE, FAILED, CANCELLED), the current state is returned unchanged \u2014 the endpoint is idempotent.", + "example": "CANCELLED" + } + }, + "required": [ + "jobId", + "state" + ] + }, + "AiJobResultResponse": { + "type": "object", + "properties": { + "actions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiJobAction" + }, + "description": "Ordered list of actions the AI took during execution. Each action represents a step such as generating a query, executing it, or synthesizing a final answer." + }, + "message": { + "type": "string", + "description": "The AI's final response message in Markdown format. This is the complete answer to the original prompt, incorporating data from all executed queries.", + "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + }, + "omniChatUrl": { + "type": "string", + "format": "uri", + "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" + }, + "resultSummary": { + "type": "string", + "description": "Summary of the job result. Typically matches the final message content.", + "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + }, + "topic": { + "type": "string", + "description": "The topic name used for query generation.", + "example": "order_items" + } + }, + "additionalProperties": {} + }, + "AiJobAction": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "The AI's explanation of what it is doing in this step, written in natural language.", + "example": "I'll generate a query to find the top 5 products by total revenue." + }, + "result": { + "$ref": "#/components/schemas/AiJobActionQueryResult" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp when this action occurred.", + "example": "2025-01-15T10:00:10.000Z" + }, + "type": { + "type": "string", + "description": "The type of action. Common types include \"generate_query\" (query generation and execution) and \"summarize\" (final answer synthesis).", + "example": "generate_query" + } + }, + "required": [ + "message", + "timestamp", + "type" + ], + "additionalProperties": {} + }, + "AiJobActionQueryResult": { + "type": "object", + "properties": { + "csvResult": { + "type": "string", + "description": "Query results formatted as CSV text.", + "example": "Name,Total Revenue\nRay-Ban Sunglasses,\"678,994.41\"\nLevi's 501 Jeans,\"475,072.00\"" + }, + "csvResultWasTruncated": { + "type": "boolean", + "description": "Whether the CSV data was truncated due to size limits. If true, the full result set may contain additional rows not included in csvResult.", + "example": false + }, + "hasResults": { + "type": "boolean", + "description": "Whether the query returned any data rows.", + "example": true + }, + "query": { + "type": "object", + "additionalProperties": {}, + "description": "The semantic query definition that was executed. This can be used with the POST /api/v1/query/run endpoint to re-run the query." + }, + "queryName": { + "type": "string", + "description": "Human-readable name describing what this query retrieves.", + "example": "Top 5 Products by Revenue" + }, + "resultId": { + "type": "string", + "description": "Stable, unique identifier for this query result within the job. Use it to reference a specific result \u2014 for example, to correlate or de-duplicate results across responses.", + "example": "928c5838-000d-4943-b305-f6242c1b4922" + }, + "status": { + "type": "string", + "enum": [ + "success", + "error" + ], + "description": "Whether the query executed successfully.", + "example": "success" + }, + "totalRowCount": { + "type": "integer", + "description": "Total number of rows returned by the query.", + "example": 5 + } + }, + "required": [ + "csvResult", + "csvResultWasTruncated", + "hasResults", + "query", + "queryName", + "status", + "totalRowCount" + ], + "description": "Query result data. Only present for generate_query action types." + }, + "ApiError422": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "No Arrow IPC data available for visualization" + } + }, + "required": [ + "error" + ] + }, + "AiBrandingResponse": { + "type": "object", + "properties": { + "body": { + "type": "string", + "description": "Body / description copy shown beneath the headline on AI helper landing surfaces.", + "example": "I can help answer data questions, build a Dashboard, or create an App." + }, + "headline": { + "type": "string", + "description": "Short headline shown on AI helper landing surfaces.", + "example": "What would you like to know?" + }, + "logoUrl": { + "type": [ + "string", + "null" + ], + "format": "uri", + "description": "Absolute URL to a custom AI helper logo. `null` when the org has not configured a custom logo \u2014 clients should render their default avatar (e.g. Blobby).", + "example": "https://example.com/blobby.png" + }, + "name": { + "type": "string", + "description": "Display name for the AI helper. Defaults to `Omni Agent` when no custom branding is set.", + "example": "Blobby" + }, + "placeholder": { + "type": "string", + "description": "Placeholder text for the AI helper's prompt input.", + "example": "Ask a question about your data..." + } + }, + "required": [ + "body", + "headline", + "logoUrl", + "name", + "placeholder" + ] + }, + "AiConversationsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiConversation" + }, + "description": "Conversations ordered by updatedAt descending." + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "PageInfo": { + "type": "object", + "properties": { + "hasNextPage": { + "type": "boolean", + "description": "Whether more results are available" + }, + "nextCursor": { + "type": [ + "string", + "null" + ], + "description": "Cursor for fetching the next page" + }, + "pageSize": { + "type": "number", + "description": "Number of results per page" + }, + "totalRecords": { + "type": "number", + "description": "Total number of records matching the query" + } + }, + "required": [ + "hasNextPage", + "nextCursor", + "pageSize", + "totalRecords" + ] + }, + "AiConversation": { + "type": "object", + "properties": { + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When the conversation was started.", + "example": "2025-01-15T10:00:00.000Z" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Conversation ID. Pass as conversationId on subsequent /api/v1/ai/jobs submissions to continue this conversation.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "lastPrompt": { + "type": [ + "string", + "null" + ], + "description": "The most recent user prompt in this conversation, useful for displaying a one-line summary in a list.", + "example": "What were our top products last week?" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Conversation title. Set by the AI after the first turn; null on brand-new sessions.", + "example": "Top products last week" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When the conversation was last touched (most recent prompt or AI activity).", + "example": "2025-01-15T10:01:30.000Z" + } + }, + "required": [ + "createdAt", + "id", + "lastPrompt", + "name", + "updatedAt" + ] + }, + "AiConversationDetailResponse": { + "type": "object", + "properties": { + "createdAt": { + "type": "string", + "format": "date-time" + }, + "id": { + "type": "string", + "format": "uuid" + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiConversationMessage" + }, + "description": "Messages in chronological order. Alternating user / assistant turns." + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + }, + "required": [ + "createdAt", + "id", + "messages", + "name", + "updatedAt" + ] + }, + "AiConversationMessage": { + "type": "object", + "properties": { + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When this turn was recorded.", + "example": "2025-01-15T10:00:00.000Z" + }, + "jobId": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "The agentic job that produced this assistant turn. Only set for assistant messages \u2014 clients use it to fetch the rendered chart via GET /api/v1/ai/jobs/{jobId}/vis. Null when the turn predates jobs or when we could not associate one.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "omniChatUrl": { + "type": [ + "string", + "null" + ], + "format": "uri", + "description": "Deep link to the assistant turn in the Omni chat UI. Null for user turns, and for assistant turns produced outside the Agentic API (where no AgenticJob row exists).", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" + }, + "role": { + "type": "string", + "enum": [ + "user", + "assistant" + ], + "description": "Speaker \u2014 `user` for prompts the user submitted, `assistant` for Blobby's responses.", + "example": "user" + }, + "text": { + "type": "string", + "description": "Markdown content of the message. For assistant turns this is the same string returned by /api/v1/ai/jobs/{jobId}/result#message.", + "example": "What were our top products last week?" + } + }, + "required": [ + "createdAt", + "jobId", + "omniChatUrl", + "role", + "text" + ] + }, + "AiCreditControlsResponse": { + "type": "object", + "properties": { + "accountCreditLimit": { + "type": "number", + "minimum": 0, + "description": "Monthly AI credit limit for the whole Omni account (shared across every org under the same Salesforce account), not just this org. 0 when no limit is configured.", + "example": 2000 + }, + "creditsUsed": { + "type": "number", + "minimum": 0, + "description": "This org's credit usage in the current billing period.", + "example": 450 + }, + "downgradeCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Downgrade threshold, or `null` if the downgrade control is off.", + "example": 800 + }, + "periodEnd": { + "type": "integer", + "minimum": 0, + "description": "End of the current billing period as a Unix ms timestamp (UTC calendar-month boundary)." + }, + "periodStart": { + "type": "integer", + "minimum": 0, + "description": "Start of the current billing period as a Unix ms timestamp (UTC calendar-month boundary)." + }, + "shutoffCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Shutoff threshold, or `null` if the shutoff control is off.", + "example": 1200 + }, + "userDefaultCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Default per-user AI credit limit, or `null` when users are unlimited by default.", + "example": 100 + } + }, + "required": [ + "accountCreditLimit", + "creditsUsed", + "downgradeCredits", + "periodEnd", + "periodStart", + "shutoffCredits", + "userDefaultCredits" + ] + }, + "AiCreditControlsUpdateBody": { + "type": "object", + "properties": { + "downgradeCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Credit usage at which AI downgrades to a cheaper model. Omit to leave unchanged, `null` to turn off, or a non-negative number to set. Must be at or below shutoffCredits.", + "example": 800 + }, + "shutoffCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Credit usage at which AI shuts off entirely. Omit to leave unchanged, `null` to turn off, or a non-negative number to set.", + "example": 1200 + }, + "userDefaultCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Default per-user AI credit limit for the billing period \u2014 what every user without an individual limit gets. Omit to leave unchanged, `null` for unlimited by default, or a non-negative number to set.", + "example": 100 + } + }, + "additionalProperties": false + }, + "AiCreditControlsUsersListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "creditLimit": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "The user's individual AI credit limit, or `null` for an explicit unlimited override.", + "example": 50 + }, + "userId": { + "type": "string", + "description": "The user's id within this organization.", + "example": "f4a2b3c8-0d1e-4f5a-9b6c-7d8e9f0a1b2c" + } + }, + "required": [ + "creditLimit", + "userId" + ] + }, + "description": "Users with an individual AI credit limit, ordered by userId ascending." + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "AiUserCreditLimitsResponse": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "type": "object", + "properties": { + "creditLimit": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "The user's effective AI credit limit, or `null` for unlimited.", + "example": 50 + }, + "userId": { + "type": "string", + "description": "The user's id within this organization.", + "example": "f4a2b3c8-0d1e-4f5a-9b6c-7d8e9f0a1b2c" + }, + "usesDefaultLimit": { + "type": "boolean", + "description": "True when the user has no individual limit and follows the org default." + } + }, + "required": [ + "creditLimit", + "userId", + "usesDefaultLimit" + ] + } + } + }, + "required": [ + "users" + ] + }, + "AiUserCreditLimitsUpdateBody": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiUserCreditLimitEntry" + }, + "minItems": 1, + "maxItems": 1000, + "description": "Users to update, at most 1000 per request. Each entry has a `userId` plus exactly one of `creditLimit` (number or `null`) or `useDefaultLimit: true`." + } + }, + "required": [ + "users" + ], + "additionalProperties": false + }, + "AiUserCreditLimitEntry": { + "type": "object", + "properties": { + "creditLimit": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "The user's individual AI credit limit for the billing period, or `null` for unlimited. Either way this overrides the org default. Mutually exclusive with `useDefaultLimit`.", + "example": 50 + }, + "useDefaultLimit": { + "type": "boolean", + "enum": [ + true + ], + "description": "Removes the user's individual limit so they follow the org default. Mutually exclusive with `creditLimit`." + }, + "userId": { + "type": "string", + "description": "The user's id within this organization.", + "example": "f4a2b3c8-0d1e-4f5a-9b6c-7d8e9f0a1b2c" + } + }, + "required": [ + "userId" + ], + "additionalProperties": false + }, + "RoutinesListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoutineResponse" + }, + "description": "Routines returned for this request, newest first." + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "RoutineResponse": { + "type": "object", + "properties": { + "branchId": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Branch of the shared model the prompt runs against, or null." + }, + "createdAt": { + "type": "string", + "description": "ISO 8601 timestamp when the routine was created." + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Display-only notes about the routine, or null." + }, + "destination": { + "$ref": "#/components/schemas/RoutineDestinationResponse" + }, + "disabled": { + "type": "boolean", + "description": "Whether the owner has paused the routine." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the routine." + }, + "lastRun": { + "$ref": "#/components/schemas/RoutineLastRun" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The shared model the prompt runs against." + }, + "name": { + "type": "string", + "description": "Customer-visible name of the routine. Used as the email subject for email destinations, and shown on Slack deliveries." + }, + "prompt": { + "type": "string", + "description": "Natural language prompt Omni runs on each scheduled run." + }, + "recipientCount": { + "type": "integer", + "description": "Number of distinct deliverable recipients. For email, user groups are expanded to members and duplicates removed; a Slack routine is always 1 (its single channel or DM)." + }, + "schedule": { + "type": "string", + "description": "Six-field cron expression (minute, hour, day-of-month, month, day-of-week, year; use `?` for an unspecified day field)." + }, + "systemDisabled": { + "type": "boolean", + "description": "Whether Omni disabled the routine because it could no longer run successfully or safely." + }, + "systemDisabledReason": { + "type": [ + "string", + "null" + ], + "description": "Reason Omni disabled the routine, or null." + }, + "timezone": { + "type": "string", + "description": "IANA timezone identifier used to evaluate the schedule." + }, + "topicName": { + "type": [ + "string", + "null" + ], + "description": "Topic scoping query generation, or null." + }, + "updatedAt": { + "type": "string", + "description": "ISO 8601 timestamp when the routine was last updated." + } + }, + "required": [ + "branchId", + "createdAt", + "description", + "destination", + "disabled", + "id", + "lastRun", + "modelId", + "name", + "prompt", + "recipientCount", + "schedule", + "systemDisabled", + "systemDisabledReason", + "timezone", + "topicName", + "updatedAt" + ] + }, + "RoutineDestinationResponse": { + "oneOf": [ + { + "$ref": "#/components/schemas/RoutineEmailDestinationResponse" + }, + { + "$ref": "#/components/schemas/RoutineSlackDestination" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "email": "#/components/schemas/RoutineEmailDestinationResponse", + "slack": "#/components/schemas/RoutineSlackDestination" + } + }, + "description": "Delivery configuration for the routine." + }, + "RoutineEmailDestinationResponse": { + "type": "object", + "properties": { + "recipientEmails": { + "type": "array", + "items": { + "type": "string", + "format": "email" + }, + "description": "Email addresses configured as direct recipients of each scheduled run, resolved from their current membership.", + "example": [ + "alice@example.com", + "bob@example.com" + ] + }, + "type": { + "type": "string", + "enum": [ + "email" + ], + "description": "Selects email delivery \u2014 each scheduled run is sent to the listed email recipients and user groups.", + "example": "email" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "User group IDs whose active members receive each scheduled run. Omni expands each group to the members' current email addresses when the routine runs.", + "example": [ + "550e8400-e29b-41d4-a716-446655440000" + ] + } + }, + "required": [ + "recipientEmails", + "type", + "userGroupIds" + ], + "additionalProperties": false + }, + "RoutineSlackDestination": { + "type": "object", + "properties": { + "recipientId": { + "type": "string", + "minLength": 1, + "description": "The Slack channel ID (e.g. \"C01234567\") or user ID (e.g. \"U01234567\") that receives each scheduled run. Exactly one recipient per Slack routine.", + "example": "C01234567" + }, + "slackRecipientType": { + "type": "string", + "enum": [ + "channel", + "users" + ], + "description": "Whether `recipientId` is a Slack channel or a user (delivered as a direct message).", + "example": "channel" + }, + "type": { + "type": "string", + "enum": [ + "slack" + ], + "description": "Selects Slack delivery \u2014 each scheduled run is posted to one Slack channel or sent as a direct message to one user.", + "example": "slack" + } + }, + "required": [ + "recipientId", + "slackRecipientType", + "type" + ], + "additionalProperties": false + }, + "RoutineLastRun": { + "type": [ + "object", + "null" + ], + "properties": { + "completedAt": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp the last completed run finished." + }, + "label": { + "type": "string", + "description": "Customer-visible status of the last completed run.", + "example": "Delivered" + }, + "state": { + "type": "string", + "description": "Machine-readable status of the last completed run.", + "example": "COMPLETE" + } + }, + "required": [ + "completedAt", + "label", + "state" + ], + "description": "Most recent completed run, or null if the routine has never completed a run." + }, + "RoutineCreateResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The unique identifier for the newly created routine.", + "example": "880e8400-e29b-41d4-a716-446655440003" + } + }, + "required": [ + "id" + ] + }, + "ApiError429": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "User has reached the maximum of 100 routines" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 429 + } + }, + "required": [ + "detail", + "status" + ] + }, + "RoutineCreateBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "description": { + "type": "string", + "maxLength": 2000, + "description": "Optional human-readable notes about the routine. Display-only \u2014 never used as model input.", + "example": "Weekly signups summary for the growth team." + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The UUID of the shared model the prompt runs against. Only shared models are supported.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 512, + "description": "Customer-visible name of the routine. Used as the email subject for email destinations, and shown on Slack deliveries.", + "example": "Weekly user signups" + }, + "prompt": { + "type": "string", + "minLength": 1, + "description": "Natural language prompt Omni runs on each scheduled run.", + "example": "How many users signed up last week?" + }, + "schedule": { + "type": "string", + "minLength": 1, + "description": "Six-field cron expression (minute, hour, day-of-month, month, day-of-week, year; use `?` for an unspecified day field). Minimum frequency is once per hour; contact Omni support if you need more frequent scheduling.", + "example": "0 9 ? * MON *" + }, + "timezone": { + "type": "string", + "minLength": 1, + "description": "IANA timezone identifier used to evaluate the schedule.", + "example": "America/New_York" + }, + "topicName": { + "type": "string", + "maxLength": 256, + "description": "Topic name to scope query generation. If omitted, the AI picks the best topic.", + "example": "users" + }, + "destination": { + "$ref": "#/components/schemas/RoutineDestination" + } + }, + "required": [ + "modelId", + "name", + "prompt", + "schedule", + "timezone", + "destination" + ], + "additionalProperties": false + }, + "RoutineDestination": { + "oneOf": [ + { + "$ref": "#/components/schemas/RoutineEmailDestination" + }, + { + "$ref": "#/components/schemas/RoutineSlackDestination" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "email": "#/components/schemas/RoutineEmailDestination", + "slack": "#/components/schemas/RoutineSlackDestination" + } + }, + "description": "Single delivery destination for the routine. To send results to multiple destinations, create one routine per destination. Omni runs the prompt once per scheduled run using the routine owner's permissions, and every recipient receives the same result regardless of their own permissions." + }, + "RoutineEmailDestination": { + "type": "object", + "properties": { + "recipientEmails": { + "type": "array", + "items": { + "type": "string", + "format": "email" + }, + "maxItems": 100, + "default": [], + "description": "Email addresses that receive each scheduled run of the routine.", + "example": [ + "alice@example.com", + "bob@example.com" + ] + }, + "type": { + "type": "string", + "enum": [ + "email" + ], + "description": "Selects email delivery \u2014 each scheduled run is sent to the listed email recipients and user groups.", + "example": "email" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "maxItems": 100, + "default": [], + "description": "User group IDs whose active members receive each scheduled run. Omni expands each group to the members' current email addresses when the routine runs.", + "example": [ + "550e8400-e29b-41d4-a716-446655440000" + ] + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + "RoutineUpdateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 2000, + "description": "Display-only notes about the routine. Pass null to clear it." + }, + "destination": { + "$ref": "#/components/schemas/RoutineDestination" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 512, + "description": "New customer-visible name of the routine. Used as the email subject for email destinations, and shown on Slack deliveries." + }, + "prompt": { + "type": "string", + "minLength": 1, + "description": "New natural language prompt Omni runs on each scheduled run." + }, + "schedule": { + "type": "string", + "minLength": 1, + "description": "New six-field cron expression (minute, hour, day-of-month, month, day-of-week, year; use `?` for an unspecified day field). Minimum frequency is once per hour." + }, + "timezone": { + "type": "string", + "minLength": 1, + "description": "New IANA timezone identifier used to evaluate the schedule." + } + }, + "additionalProperties": false + }, + "RoutineDeleteResponse": { + "type": "object", + "properties": { + "deleted": { + "type": "boolean", + "enum": [ + true + ], + "description": "Always true on a successful delete." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The deleted routine\u2019s ID." + } + }, + "required": [ + "deleted", + "id" + ] + }, + "RoutineTriggerResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The ID of the run (scheduled job) that was started.", + "example": "990e8400-e29b-41d4-a716-446655440004" + } + }, + "required": [ + "id" + ] + }, + "ApiKeyListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApiKey" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "ApiKey": { + "type": "object", + "properties": { + "createdAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of when the token was created", + "example": "2026-01-15T10:00:00.000Z" + }, + "enabled": { + "type": "boolean", + "description": "Whether the token can currently authenticate. A disabled token cannot authenticate but remains visible until deleted.", + "example": true + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the token", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "membershipId": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Membership ID of the user the token is scoped to. Null for organization-level tokens.", + "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" + }, + "name": { + "type": "string", + "description": "Human-readable name for the token", + "example": "CI deployment key" + }, + "type": { + "type": "string", + "enum": [ + "organization", + "personal", + "mcp" + ], + "description": "Token type: `organization` (org-level), `personal` (user-created personal access token), or `mcp` (MCP OAuth grant).", + "example": "organization" + } + }, + "required": [ + "createdAt", + "enabled", + "id", + "membershipId", + "name", + "type" + ] + }, + "ApiKeyUpdateBody": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Set to `false` to disable the token, `true` to re-enable it.", + "example": false + } + }, + "required": [ + "enabled" + ], + "additionalProperties": false + }, + "ApiKeyDeleteResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Human-readable description of the outcome", + "example": "API token revoked" + }, + "success": { + "type": "boolean", + "enum": [ + true + ], + "description": "Always `true` on a successful revocation" + } + }, + "required": [ + "message", + "success" + ] + }, + "DbtEnvironmentListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtEnvironmentItem" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "DbtEnvironmentItem": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique environment identifier" + }, + "isDefaultEnvironment": { + "type": "boolean", + "description": "Whether this is the default environment" + }, + "isDeferralEnabled": { + "type": "boolean", + "description": "Whether dbt deferral is enabled for this environment. Always false for the default (production) environment \u2014 the backend rejects enabling it there." + }, + "name": { + "type": "string", + "description": "Environment name" + }, + "ownerId": { + "type": [ + "string", + "null" + ], + "description": "User ID of the environment owner, or null if not a personal environment" + }, + "targetDatabase": { + "type": [ + "string", + "null" + ], + "description": "Target database override" + }, + "targetName": { + "type": [ + "string", + "null" + ], + "description": "Target name override" + }, + "targetRole": { + "type": [ + "string", + "null" + ], + "description": "Target role override" + }, + "targetSchema": { + "type": "string", + "description": "Target schema" + }, + "variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtEnvironmentResponseVariable" + }, + "description": "Environment variables" + } + }, + "required": [ + "id", + "isDefaultEnvironment", + "isDeferralEnabled", + "name", + "ownerId", + "targetDatabase", + "targetName", + "targetRole", + "targetSchema", + "variables" + ] + }, + "DbtEnvironmentResponseVariable": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Variable ID" + }, + "isSecret": { + "type": "boolean", + "description": "Whether the variable value is secret" + }, + "name": { + "type": "string", + "description": "Variable name" + }, + "value": { + "type": [ + "string", + "null" + ], + "description": "Variable value (null for secret variables)" + } + }, + "required": [ + "id", + "isSecret", + "name", + "value" + ] + }, + "DbtEnvironmentCreateBody": { + "type": "object", + "properties": { + "isDeferralEnabled": { + "type": "boolean", + "default": false, + "description": "Whether to enable dbt deferral for this environment. Ignored (forced to false) for the default (production) environment.", + "example": false + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Environment name", + "example": "PR_1111_Expose" + }, + "ownerId": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", + "example": null + }, + "targetDatabase": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target database override", + "example": "analytics_dev" + }, + "targetName": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target name override", + "example": null + }, + "targetRole": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target role override", + "example": null + }, + "targetSchema": { + "type": "string", + "minLength": 1, + "description": "Target schema for this environment", + "example": "PR_1111_Expose" + }, + "variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtEnvironmentVariable" + }, + "default": [], + "description": "Environment variables" + } + }, + "required": [ + "name", + "targetSchema" + ] + }, + "DbtEnvironmentVariable": { + "type": "object", + "properties": { + "isSecret": { + "type": "boolean", + "description": "Whether the variable value is secret" + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Variable name" + }, + "value": { + "type": "string", + "description": "Variable value" + } + }, + "required": [ + "isSecret", + "name", + "value" + ] + }, + "DbtEnvironmentUpdateBody": { + "type": "object", + "properties": { + "isDeferralEnabled": { + "type": "boolean", + "default": false, + "description": "Whether to enable dbt deferral for this environment. Ignored (forced to false) for the default (production) environment.", + "example": false + }, + "name": { + "type": "string", + "minLength": 1, + "description": "Environment name", + "example": "PR_1111_Expose" + }, + "ownerId": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", + "example": null + }, + "targetDatabase": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target database override", + "example": "analytics_dev" + }, + "targetName": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target name override", + "example": null + }, + "targetRole": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target role override", + "example": null + }, + "targetSchema": { + "type": "string", + "minLength": 1, + "description": "Target schema for this environment", + "example": "PR_1111_Expose" + }, + "variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtEnvironmentVariableUpdateOrNew" + }, + "default": [], + "description": "Environment variables. Variables with an id update existing ones; variables without an id create new ones." + } + }, + "required": [ + "name", + "targetSchema" + ] + }, + "DbtEnvironmentVariableUpdateOrNew": { + "oneOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentVariableUpdate" + }, + { + "$ref": "#/components/schemas/DbtEnvironmentVariable" + } + ] + }, + "DbtEnvironmentDeleteResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Confirmation message", + "example": "dbt environment deleted successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the deletion was successful", + "example": true + } + }, + "required": [ + "message", + "success" + ] + }, + "ContentListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/ApiDocument" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "document" + ] + } + }, + "required": [ + "type" + ] + } + ] + }, + { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Content name" + }, + "owner": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "User ID of the owner" + }, + "name": { + "type": "string", + "description": "Name of the owner" + } + }, + "required": [ + "id", + "name" + ], + "description": "Content owner" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Content access scope" + }, + "_count": { + "type": "object", + "properties": { + "documents": { + "type": "number", + "description": "Number of documents" + }, + "favorites": { + "type": "number", + "description": "Number of users who favorited" + } + }, + "required": [ + "documents", + "favorites" + ], + "description": "Folder counts" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels" + }, + "path": { + "type": "string", + "description": "Full path to the folder", + "example": "sales-reports/q1-2026" + }, + "url": { + "type": "string", + "description": "URL to view the folder in the Omni UI.", + "example": "https://org.omni.co/f/sales-reports" + }, + "type": { + "type": "string", + "enum": [ + "folder" + ] + } + }, + "required": [ + "id", + "name", + "owner", + "scope", + "path", + "url", + "type" + ] + } + ] + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "OwnerInternal": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Owner membership ID" + }, + "name": { + "type": "string", + "description": "Owner display name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Content owner" + }, + "ContentShareScope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Content access scope" + }, + "InternalFolder": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "description": "Folder ID" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Folder name" + }, + "path": { + "type": "string", + "description": "Folder path" + }, + "scope": { + "$ref": "#/components/schemas/ContentShareScope" + } + }, + "required": [ + "id", + "name", + "path", + "scope" + ], + "description": "Parent folder" + }, + "ApiDocument": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Content name" + }, + "owner": { + "$ref": "#/components/schemas/OwnerInternal" + }, + "scope": { + "$ref": "#/components/schemas/ContentShareScope" + }, + "_count": { + "type": "object", + "properties": { + "favorites": { + "type": "number", + "description": "Number of users who favorited" + }, + "views": { + "type": "number", + "description": "Number of views" + } + }, + "required": [ + "favorites", + "views" + ], + "description": "Document counts" + }, + "connectionId": { + "type": "string", + "description": "Connection ID" + }, + "deleted": { + "type": "boolean", + "description": "Whether document is deleted" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "folder": { + "$ref": "#/components/schemas/InternalFolder" + }, + "hasApp": { + "type": "boolean", + "description": "Whether document has an app" + }, + "hasDashboard": { + "type": "boolean", + "description": "Whether document has a dashboard" + }, + "identifier": { + "type": "string", + "description": "Document identifier" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Applied labels" + }, + "lastViewedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Last time the dashboard was viewed" + }, + "updatedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Last updated timestamp" + }, + "url": { + "type": "string", + "description": "URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an app, otherwise the workbook URL.", + "example": "https://org.omni.co/dashboards/abc123" + }, + "visits": { + "type": [ + "number", + "null" + ], + "description": "Number of dashboard visits" + } + }, + "required": [ + "name", + "owner", + "scope", + "connectionId", + "deleted", + "folder", + "hasApp", + "hasDashboard", + "identifier", + "updatedAt", + "url" + ] + }, + "DashboardsDownloadResponse": { + "type": "object", + "properties": { + "job_id": { + "type": "string", + "format": "uuid", + "description": "ID of the download job. Use this to poll for download status.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "message": { + "type": "string", + "description": "Status message", + "example": "Download initiated successfully" + } + }, + "required": [ + "job_id", + "message" + ] + }, + "DashboardsDownloadBody": { + "type": "object", + "properties": { + "enableFormatting": { + "type": "boolean", + "default": false, + "description": "Compatible with csv, xlsx & json formats. If true, formatting will be enabled in the output. Note: If true for json format, a queryIdentifierMapKey is required.", + "example": false + }, + "expandTablesToShowAllRows": { + "type": "boolean", + "description": "Compatible with pdf and png formats. If true, up to 1,000 rows in table visualizations will be included in the delivery. Note: This parameter cannot be used when paperFormat: fit_page.", + "example": false + }, + "filterConfig": { + "description": "An object specifying the filter conditions to apply to the task. The filter key specified must already exist in the dashboard.", + "example": { + "status": [ + "active", + "pending" + ] + } + }, + "format": { + "type": "string", + "enum": [ + "pdf", + "png", + "csv", + "xlsx", + "json" + ], + "description": "Output format for the download: pdf, png, csv, xlsx, or json", + "example": "pdf" + }, + "hideHiddenFields": { + "type": "boolean", + "default": false, + "description": "Compatible with csv & xlsx formats. If true, fields marked as hidden won't be displayed in the output.", + "example": false + }, + "hideTitle": { + "type": "boolean", + "default": false, + "description": "Compatible with pdf & png formats. If true, the content's title will be hidden in the output.", + "example": false + }, + "maxRowLimit": { + "type": "number", + "minimum": 1, + "description": "Compatible with csv, json, & xlsx formats. Used with overrideRowLimit. Specifies the maximum number of rows.", + "example": 1000 + }, + "overrideRowLimit": { + "type": "boolean", + "default": false, + "description": "Compatible with csv, json, & xlsx formats. If true, the default row limit will be overridden. Note: If true for json and xlsx formats, a queryIdentifierMapKey is required.", + "example": false + }, + "paperFormat": { + "type": "string", + "enum": [ + "a3", + "a4", + "fit_page", + "legal", + "letter", + "tabloid" + ], + "description": "Compatible with pdf formats. Defines the paper format (size) of the resulting PDF. Must be one of: a3, a4, letter, legal, fit_page, tabloid.", + "example": "letter" + }, + "paperOrientation": { + "type": "string", + "enum": [ + "portrait", + "landscape" + ], + "description": "Compatible with pdf formats. Defines the paper orientation of the resulting PDF. Must be one of: portrait, landscape.", + "example": "landscape" + }, + "queryIdentifierMapKey": { + "type": "string", + "description": "Required for single tile tasks. The ID of the query to include in a single tile task. Must reference a valid query in the dashboard.", + "example": "Jmn2r3KV" + }, + "showContentLink": { + "type": "boolean", + "default": true, + "description": "Compatible with all formats except link_only. If true, a link to the content will be shown in the output.", + "example": true + }, + "showFilters": { + "type": "boolean", + "default": true, + "description": "Compatible with all formats except link_only & csv. If true, filters will be shown in the output.", + "example": true + }, + "singleColumnLayout": { + "type": "boolean", + "description": "Compatible with pdf and png formats. If true, dashboard tiles will be arranged into a single vertical column.", + "example": false + }, + "useCache": { + "type": "boolean", + "default": false, + "description": "If true, allow scheduled queries to use cached results instead of always running fresh queries.", + "example": false + }, + "filename": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Custom filename for the downloaded file (without extension)", + "example": "monthly-report" + } + }, + "required": [ + "format" + ], + "additionalProperties": false + }, + "DashboardFiltersResponse": { + "type": "object", + "properties": { + "controls": { + "description": "Control configuration object. Keys are control IDs, values contain controlType, filterId, label, etc." + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of filter IDs defining display order", + "example": [ + "filter_abc123", + "filter_def456" + ] + }, + "filters": { + "description": "Filter configuration object. Keys are filter IDs, values contain fieldName, viewName, kind, defaultValue, etc." + }, + "identifier": { + "type": "string", + "description": "Dashboard identifier", + "example": "12db1a0a" + } + }, + "required": [ + "filterOrder", + "identifier" + ] + }, + "DashboardsUpdateFiltersBody": { + "type": "object", + "properties": { + "clearExistingDraft": { + "type": "boolean", + "default": false, + "description": "When true, discards any existing draft before applying updates. Required when updating a published document that already has a draft." + }, + "controls": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": {}, + "additionalProperties": {} + }, + "description": "Partial control updates. Keys are control IDs that must exist in the dashboard." + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "New order for filters. All filter IDs must exist in the dashboard." + }, + "filters": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": {}, + "additionalProperties": {} + }, + "description": "Partial filter updates. Keys are filter IDs that must exist in the dashboard." + } + } + }, + "DocumentsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Document" + }, + "description": "List of documents" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "Document": { + "type": "object", + "properties": { + "_count": { + "type": "object", + "properties": { + "favorites": { + "type": "number", + "description": "Number of users who favorited this document" + }, + "views": { + "type": "number", + "description": "Number of views" + } + }, + "required": [ + "favorites", + "views" + ], + "description": "Document counts (included when _count is in include param)" + }, + "connectionId": { + "type": "string", + "description": "Connection ID the document is associated with" + }, + "deleted": { + "type": "boolean", + "description": "Whether the document is deleted (archived)" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "folder": { + "$ref": "#/components/schemas/DocumentFolder" + }, + "hasApp": { + "type": "boolean", + "description": "Whether the document has an associated app" + }, + "hasDashboard": { + "type": "boolean", + "description": "Whether the document has an associated dashboard" + }, + "identifier": { + "type": "string", + "description": "Document identifier", + "example": "abc123" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels applied to the document (included when labels is in include param)" + }, + "name": { + "type": "string", + "description": "Document name" + }, + "owner": { + "$ref": "#/components/schemas/DocumentOwner" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Document access scope" + }, + "type": { + "type": "string", + "enum": [ + "document" + ], + "description": "Content type" + }, + "updatedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Last updated timestamp" + }, + "url": { + "type": "string", + "description": "URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an app, otherwise the workbook URL.", + "example": "https://org.omni.co/dashboards/abc123" + } + }, + "required": [ + "connectionId", + "deleted", + "folder", + "hasDashboard", + "identifier", + "name", + "owner", + "scope", + "type", + "updatedAt", + "url" + ] + }, + "DocumentFolder": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "description": "Folder ID" + }, + "name": { + "type": "string", + "description": "Folder name" + }, + "path": { + "type": "string", + "description": "Folder path" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Folder access scope" + } + }, + "required": [ + "id", + "name", + "path", + "scope" + ], + "description": "Folder containing the document" + }, + "DocumentOwner": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Owner membership ID" + }, + "name": { + "type": "string", + "description": "Owner display name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Document owner" + }, + "DocumentsCreateResponse": { + "type": "object", + "properties": { + "dashboard": { + "type": "object", + "properties": { + "dashboardId": { + "type": "string", + "description": "Dashboard ID" + }, + "id": { + "type": "string", + "description": "Dashboard ID" + } + }, + "required": [ + "dashboardId", + "id" + ], + "additionalProperties": {}, + "description": "Created dashboard" + }, + "workbook": { + "type": "object", + "properties": { + "documentId": { + "type": "string", + "description": "Document ID (deprecated)" + }, + "id": { + "type": "string", + "description": "Workbook ID" + } + }, + "required": [ + "documentId", + "id" + ], + "additionalProperties": {}, + "description": "Created workbook" + } + }, + "required": [ + "dashboard", + "workbook" + ] + }, + "DocumentsCreateBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID to associate the document with a model branch", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "facetFilters": { + "type": "boolean", + "description": "Enable facet filters on the dashboard" + }, + "filterConfig": { + "description": "Dashboard filter configuration" + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Order of filters in the dashboard" + }, + "identifier": { + "$ref": "#/components/schemas/DocumentIdentifier" + }, + "metadata": { + "description": "Dashboard metadata" + }, + "metadataVersion": { + "type": "string", + "description": "Dashboard metadata version (required when metadata is provided)" + }, + "modelId": { + "type": "string", + "description": "Shared model ID to base the document on" + }, + "name": { + "type": "string", + "description": "Document name" + }, + "queryPresentations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "aiConfig": { + "description": "AI configuration" + }, + "chartType": { + "type": [ + "string", + "null" + ], + "description": "Chart type" + }, + "description": { + "type": "string", + "maxLength": 500, + "description": "Query presentation description" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 144, + "description": "Query presentation name" + }, + "prefersChart": { + "type": "boolean", + "description": "Whether to prefer chart view" + }, + "query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Query fields" + }, + "table": { + "type": "string", + "description": "Query table/topic" + } + }, + "required": [ + "fields", + "table" + ], + "additionalProperties": {}, + "description": "Query definition" + }, + "resultConfig": { + "description": "Result configuration" + }, + "subTitle": { + "type": "string", + "maxLength": 250, + "description": "Subtitle" + }, + "topicName": { + "type": [ + "string", + "null" + ], + "maxLength": 256, + "description": "Topic name. Omit or pass null for raw-SQL tiles or any tile with no semantic topic." + }, + "visConfig": { + "$ref": "#/components/schemas/ApiVisConfig" + } + }, + "required": [ + "name", + "query" + ] + }, + "description": "Query presentations for the document" + } + }, + "required": [ + "modelId", + "name" + ] + }, + "DocumentIdentifier": { + "type": "string", + "minLength": 2, + "maxLength": 48, + "description": "Optional document identifier. If omitted, an identifier is auto-generated. Must be unique within the organization." + }, + "ApiVisConfig": { + "type": "object", + "additionalProperties": true, + "description": "Visualization configuration (Not statically modeled; use plain dicts.)" + }, + "DocumentsGetResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "documentMetadata": { + "description": "Document metadata" + }, + "facetFilters": { + "type": "boolean", + "description": "Whether facet filters are enabled" + }, + "filterConfig": { + "description": "Dashboard filter configuration" + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Order of filters" + }, + "modelId": { + "type": "string", + "description": "Model ID" + }, + "name": { + "type": "string", + "description": "Document name" + }, + "queryPresentations": { + "type": "array", + "items": {}, + "description": "Query presentations" + }, + "refreshInterval": { + "type": [ + "number", + "null" + ], + "description": "Auto-refresh interval in seconds" + } + }, + "required": [ + "facetFilters", + "filterOrder", + "modelId", + "name", + "queryPresentations", + "refreshInterval" + ] + }, + "DocumentsPutResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "identifier": { + "type": "string", + "description": "Document identifier" + }, + "name": { + "type": "string", + "description": "Updated document name" + } + }, + "required": [ + "identifier", + "name" + ] + }, + "DocumentsPutBody": { + "type": "object", + "properties": { + "clearExistingDraft": { + "type": "boolean", + "default": false, + "description": "Clear existing draft before updating (for published documents with drafts)" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "documentMetadata": { + "description": "Document presentation metadata" + }, + "facetFilters": { + "type": "boolean", + "description": "Enable facet filters" + }, + "filterConfig": { + "description": "Filter configuration" + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Order of filters" + }, + "modelId": { + "type": "string", + "description": "Model ID" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 254, + "description": "Document name" + }, + "queryPresentations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DocumentsPutQueryPresentation" + }, + "minItems": 1, + "description": "Query presentations (full replacement)" + }, + "refreshInterval": { + "type": [ + "integer", + "null" + ], + "minimum": 60, + "description": "Auto-refresh interval in seconds" + } + }, + "required": [ + "facetFilters", + "filterOrder", + "modelId", + "name", + "queryPresentations", + "refreshInterval" + ] + }, + "DocumentsPutQueryPresentation": { + "type": "object", + "properties": { + "aiConfig": { + "type": "object", + "properties": { + "description": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + }, + "subTitle": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + } + }, + "description": "AI configuration" + }, + "chartType": { + "type": [ + "string", + "null" + ], + "enum": [ + "auto", + "area", + "areaStacked", + "areaStackedPercentage", + "bar", + "barLine", + "barGrouped", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "regionMap", + "markdown", + "omni-ai-summary-markdown", + "pie", + "funnel", + "sankey", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "singleRecord", + "omni-spreadsheet", + "summaryValue", + "svgMap", + "table", + "treemap", + null + ], + "description": "Chart type" + }, + "description": { + "type": "string", + "maxLength": 500, + "description": "Description" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 144, + "description": "Query presentation name" + }, + "prefersChart": { + "type": "boolean", + "description": "Whether to prefer chart view" + }, + "query": { + "description": "Query definition" + }, + "queryIdentifierMapKey": { + "type": "string", + "pattern": "^[1-9][0-9]*$", + "description": "Round-trip preservation hint. When the value matches an existing key on the document, the tile keeps its map key (and dashboard containers stay attached). Omit for new tiles. Must be a positive integer string (e.g. \"1\", \"2\", \"10\")." + }, + "resultConfig": { + "description": "Result config" + }, + "subTitle": { + "type": "string", + "maxLength": 250, + "description": "Subtitle" + }, + "topicName": { + "type": [ + "string", + "null" + ], + "maxLength": 256, + "description": "Topic name. Omit or pass null for raw-SQL tiles or any tile with no semantic topic." + }, + "visConfig": { + "$ref": "#/components/schemas/ApiVisConfig" + } + }, + "required": [ + "name" + ] + }, + "DocumentsUpdateResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "identifier": { + "type": "string", + "description": "Document identifier" + }, + "name": { + "type": "string", + "description": "Updated document name" + } + }, + "required": [ + "identifier", + "name" + ] + }, + "DocumentsUpdateBody": { + "type": "object", + "properties": { + "clearExistingDraft": { + "type": "boolean", + "default": false, + "description": "Clear existing draft before updating (for published documents with drafts)" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "identifier": { + "$ref": "#/components/schemas/DocumentIdentifier" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 254, + "description": "New document name" + } + } + }, + "SuccessResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation was successful", + "example": true + } + }, + "required": [ + "success" + ] + }, + "DocumentsGetQueriesResponse": { + "type": "object", + "properties": { + "queries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Query presentation ID" + }, + "name": { + "type": "string", + "description": "Query presentation name" + }, + "query": { + "description": "Query JSON definition" + }, + "queryIdentifierMapKey": { + "type": "string", + "description": "Key in the query identifier map" + }, + "url": { + "type": "string", + "description": "URL to view this specific query/sheet in the workbook.", + "example": "https://org.omni.co/w/abc123?key=1" + } + }, + "required": [ + "id", + "name", + "queryIdentifierMapKey", + "url" + ] + }, + "description": "List of queries in the document" + } + }, + "required": [ + "queries" + ] + }, + "DocumentsMoveBody": { + "type": "object", + "properties": { + "folderPath": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Destination folder path (null for root)" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Access scope for the document" + } + }, + "required": [ + "folderPath" + ] + }, + "DocumentsGetPermissionsResponse": { + "type": "object", + "properties": { + "permits": { + "description": "User permits for the document" + } + } + }, + "DocumentsUpdatePermissionSettingsBody": { + "type": "object", + "properties": { + "canDownload": { + "type": "boolean", + "description": "Allow downloading" + }, + "canDrill": { + "type": "boolean", + "description": "Allow drill-down" + }, + "canSchedule": { + "type": "boolean", + "description": "Allow scheduling" + }, + "canUpload": { + "type": "boolean", + "description": "Allow uploads" + }, + "canUseDashboardAi": { + "type": "boolean", + "description": "Allow using dashboard AI" + }, + "canUseTimezoneOverride": { + "type": "boolean", + "description": "Allow timezone override" + }, + "canViewWorkbook": { + "type": "boolean", + "description": "Allow viewing workbook" + }, + "organizationAccessBoost": { + "type": "boolean", + "description": "Boost organization access" + }, + "organizationRole": { + "type": "string", + "enum": [ + "viewer", + "editor", + "manager", + "no_access" + ], + "description": "Organization-wide role for the document" + }, + "requirePullRequestToPublish": { + "type": "boolean", + "description": "Require pull request to publish changes" + } + } + }, + "DocumentsAddPermitsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "default": false, + "description": "Grant access boost" + }, + "role": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "Role to grant" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to grant access to" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User membership IDs to grant access to" + } + }, + "required": [ + "role" + ] + }, + "DocumentsUpdatePermitsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "description": "Access boost setting" + }, + "role": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "Role to set" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to update" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User membership IDs to update" + } + } + }, + "DocumentsRevokePermitsBody": { + "type": "object", + "properties": { + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to revoke access from" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User membership IDs to revoke access from" + } + } + }, + "DocumentsCreateDraftResponse": { + "type": "object", + "properties": { + "identifier": { + "type": "string", + "description": "Draft document identifier" + } + }, + "required": [ + "identifier" + ] + }, + "DocumentsCreateDraftBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Branch ID for the draft" + } + } + }, + "DocumentsDiscardDraftResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message" + } + }, + "required": [ + "message" + ] + }, + "DocumentsDiscardDraftBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Branch ID for the draft" + } + } + }, + "DocumentsListDraftsResponse": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApiDraft" + } + }, + "ApiDraft": { + "type": "object", + "properties": { + "branch": { + "$ref": "#/components/schemas/ApiDraftBranch" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When the draft was created" + }, + "createdBy": { + "$ref": "#/components/schemas/ApiDraftActor" + }, + "draftOutOfDate": { + "type": "boolean", + "description": "True when the published document was published more recently than the draft was created (the draft is based on a stale baseline)" + }, + "identifier": { + "type": "string", + "description": "Draft workbook identifier \u2014 use this to address the draft" + }, + "lastEditedBy": { + "$ref": "#/components/schemas/ApiDraftActor" + }, + "publishedIdentifier": { + "type": "string", + "description": "Identifier of the published document the draft is for" + }, + "status": { + "$ref": "#/components/schemas/ApiDraftStatus" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "Most recent edit time on the draft workbook" + }, + "workbookModelId": { + "type": "string", + "format": "uuid", + "description": "omni_model ID for the draft workbook" + } + }, + "required": [ + "branch", + "createdAt", + "createdBy", + "draftOutOfDate", + "identifier", + "lastEditedBy", + "publishedIdentifier", + "status", + "updatedAt", + "workbookModelId" + ] + }, + "ApiDraftBranch": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Branch (omni model) ID" + }, + "name": { + "type": "string", + "description": "Branch name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Branch the draft is attached to, or null for a draft on main" + }, + "ApiDraftActor": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Display name" + } + }, + "required": [ + "name" + ], + "description": "User who created the draft" + }, + "ApiDraftStatus": { + "type": "string", + "enum": [ + "active", + "archived" + ], + "description": "Lifecycle status: \"active\" for current drafts, \"archived\" for soft-deleted drafts (retained ~7 days)" + }, + "DocumentsDuplicateResponse": { + "type": "object", + "properties": { + "dashboardId": { + "type": "string", + "description": "New dashboard ID" + }, + "identifier": { + "type": "string", + "description": "New document identifier" + }, + "name": { + "type": "string", + "description": "Document name" + }, + "workbookId": { + "type": "string", + "description": "New workbook ID" + } + }, + "required": [ + "dashboardId", + "identifier", + "name", + "workbookId" + ] + }, + "DocumentsDuplicateBody": { + "type": "object", + "properties": { + "folderPath": { + "type": [ + "string", + "null" + ], + "description": "Destination folder path (null for root)" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 254, + "description": "Name for the duplicated document" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Access scope for the duplicated document" + } + }, + "required": [ + "name" + ] + }, + "DocumentsUpgradeLayoutResponse": { + "type": "object", + "properties": { + "identifier": { + "type": "string", + "description": "Document identifier" + }, + "upgraded": { + "type": "boolean", + "description": "True when the layout was upgraded, false when the document already had advanced layout (no-op)." + } + }, + "required": [ + "identifier", + "upgraded" + ] + }, + "DocumentsUpgradeLayoutBody": { + "type": "object", + "properties": { + "clearExistingDraft": { + "type": "boolean", + "default": false, + "description": "When upgrading a published document, discard any existing draft instead of failing with a conflict." + } + } + }, + "DocumentsBulkUpdateLabelsResponse": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Updated list of labels on the document" + } + }, + "required": [ + "labels" + ] + }, + "DocumentsBulkUpdateLabelsBody": { + "type": "object", + "properties": { + "add": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "Labels to add" + }, + "remove": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "Labels to remove" + } + } + }, + "DocumentsTransferOwnershipBody": { + "type": "object", + "properties": { + "userId": { + "type": "string", + "format": "uuid", + "description": "Membership ID of the new owner" + } + }, + "required": [ + "userId" + ] + }, + "DocumentsAccessListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "principals": { + "type": "array", + "items": {}, + "description": "List of users and groups with access" + } + }, + "required": [ + "pageInfo", + "principals" + ] + }, + "DocumentsListFavoritesResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DocumentFavoriteUser" + }, + "description": "Users who favorited this document" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "DocumentFavoriteUser": { + "type": "object", + "properties": { + "email": { + "type": [ + "string", + "null" + ], + "description": "Favoriting user's email. Null when the user has no resolvable email \u2014 e.g. an embed-SSO favoriter whose embed session did not provide one." + }, + "favoritedAt": { + "type": "string", + "description": "ISO 8601 timestamp when the user favorited the document" + }, + "name": { + "type": "string", + "description": "Favoriting user's display name" + }, + "userId": { + "type": "string", + "description": "Membership ID of the user who favorited the document (use with other v1 endpoints' userId parameter)" + } + }, + "required": [ + "email", + "favoritedAt", + "name", + "userId" + ] + }, + "DocumentsV2CreateResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "identifier": { + "type": "string", + "description": "Identifier of the newly created document." + }, + "name": { + "type": "string", + "description": "Document name." + } + }, + "required": [ + "description", + "identifier", + "name" + ] + }, + "DocumentsV2CreateBody": { + "type": "object", + "properties": { + "containers": { + "$ref": "#/components/schemas/ContainersOnCreate" + }, + "controls": { + "$ref": "#/components/schemas/ControlsPatchExternal" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "folderId": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Folder to create the document in. When omitted, defaults to the caller\u2019s personal \"My documents\" (requires permission to save personal content \u2014 otherwise the request is rejected)." + }, + "identifier": { + "$ref": "#/components/schemas/DocumentIdentifier" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Base workbook model the document is built on \u2014 a SHARED model, or a SHARED_EXTENSION with `allowAsWorkbookBase = true`." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 254, + "description": "Document name." + }, + "queryPresentations": { + "$ref": "#/components/schemas/QueryPresentationsPatchExternal" + }, + "settings": { + "$ref": "#/components/schemas/SettingsPatchExternal" + }, + "summary": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Optional. Caller-supplied note describing the create, written to the history audit trail. When omitted, the server auto-fills it with \"Created document\"." + } + }, + "required": [ + "modelId", + "name" + ], + "additionalProperties": false + }, + "ContainersOnCreate": { + "type": [ + "array", + "null" + ], + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "$ref": "#/components/schemas/PageContainer" + }, + { + "$ref": "#/components/schemas/StackContainer" + } + ] + }, + "description": "Container layout array, or `null` to create a workbook-only document with no dashboard. When `null`, `controls` and `settings` must be omitted." + }, + "GridContainer": { + "type": "object", + "additionalProperties": true, + "description": "Grid container \u2014 children are positioned on a grid (each carries a gridPosition). (Not statically modeled; use plain dicts.)" + }, + "StackContainer": { + "type": "object", + "additionalProperties": true, + "description": "Stack container \u2014 an ordered list of nested children (content, grid, stack, or reference). (Not statically modeled; use plain dicts.)" + }, + "ReferenceContainer": { + "type": "object", + "additionalProperties": true, + "description": "Reference container \u2014 points at another container in the collection by its instanceKey. (Not statically modeled; use plain dicts.)" + }, + "PageContainer": { + "type": "object", + "additionalProperties": true, + "description": "Page container \u2014 a top-level page wrapping a single grid, stack, or reference container, optionally per breakpoint/media. (Not statically modeled; use plain dicts.)" + }, + "ControlsPatchExternal": { + "type": "object", + "additionalProperties": true, + "description": "(Not statically modeled; use plain dicts.)" + }, + "ControlPatchExternal": { + "type": "object", + "additionalProperties": true, + "description": "(Not statically modeled; use plain dicts.)" + }, + "JsonValue": { + "type": "object", + "additionalProperties": true, + "description": "Arbitrary JSON value (string, number, boolean, null, object, or array). (Not statically modeled; use plain dicts.)" + }, + "QueryPresentationsPatchExternal": { + "type": "object", + "additionalProperties": true, + "description": "(Not statically modeled; use plain dicts.)" + }, + "QueryPresentationPatchExternal": { + "type": "object", + "additionalProperties": true, + "description": "(Not statically modeled; use plain dicts.)" + }, + "SettingsPatchExternal": { + "type": "object", + "properties": { + "crossfilterEnabled": { + "type": "boolean", + "description": "When true, clicking a value in one tile filters all other tiles on the dashboard." + }, + "customText": { + "type": [ + "object", + "null" + ], + "properties": { + "queryError": { + "type": "string", + "description": "Custom text shown when a query errors, replacing the default error text." + }, + "queryNoResults": { + "type": "string", + "description": "Custom text shown when a query returns no results, replacing the default empty state." + } + }, + "description": "Custom text replacing default UI strings on the dashboard, e.g. when queries error or return no results." + }, + "facetFilters": { + "type": "boolean", + "description": "When true, dashboard filters are applied per-facet when faceting is active." + }, + "refreshInterval": { + "type": [ + "number", + "null" + ], + "description": "Auto-refresh interval in seconds. Null disables auto-refresh." + }, + "runQueriesOn": { + "type": [ + "string", + "null" + ], + "enum": [ + "current-page", + "all-pages", + null + ], + "description": "Controls whether dashboard queries execute on the visible page or across all pages." + } + }, + "description": "Document settings. Shallow-merged with the existing settings." + }, + "DocumentsV2ReadResponse": { + "type": "object", + "properties": { + "containers": { + "$ref": "#/components/schemas/Containers" + }, + "controls": { + "$ref": "#/components/schemas/ControlsReadExternal" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Base model the document is built on (the `modelId` supplied at create). Immutable \u2014 echoed here so a GET round-trips through PATCH; supplying a different value on PATCH is rejected." + }, + "name": { + "type": "string", + "maxLength": 254, + "description": "Document name." + }, + "queryPresentations": { + "$ref": "#/components/schemas/QueryPresentationsReadExternal" + }, + "settings": { + "$ref": "#/components/schemas/SettingsReadExternal" + } + }, + "required": [ + "description", + "modelId", + "name", + "queryPresentations" + ] + }, + "Containers": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true + }, + "description": "Container layout array (grid / stack / page / reference containers, recursively nested). The server validates the full structure on apply. (Not statically modeled; use plain dicts.)" + }, + "ControlsReadExternal": { + "type": "object", + "additionalProperties": true, + "description": "(Not statically modeled; use plain dicts.)" + }, + "ControlReadExternal": { + "type": "object", + "additionalProperties": true, + "description": "(Not statically modeled; use plain dicts.)" + }, + "QueryPresentationsReadExternal": { + "type": "object", + "additionalProperties": true, + "description": "(Not statically modeled; use plain dicts.)" + }, + "QueryPresentationReadExternal": { + "type": "object", + "additionalProperties": true, + "description": "(Not statically modeled; use plain dicts.)" + }, + "SettingsReadExternal": { + "type": "object", + "properties": { + "crossfilterEnabled": { + "type": "boolean", + "description": "When true, clicking a value in one tile filters all other tiles on the dashboard." + }, + "customText": { + "type": [ + "object", + "null" + ], + "properties": { + "queryError": { + "type": "string", + "description": "Custom text shown when a query errors, replacing the default error text." + }, + "queryNoResults": { + "type": "string", + "description": "Custom text shown when a query returns no results, replacing the default empty state." + } + }, + "description": "Custom text replacing default UI strings on the dashboard, e.g. when queries error or return no results." + }, + "facetFilters": { + "type": "boolean", + "description": "When true, dashboard filters are applied per-facet when faceting is active." + }, + "refreshInterval": { + "type": [ + "number", + "null" + ], + "description": "Auto-refresh interval in seconds. Null disables auto-refresh." + }, + "runQueriesOn": { + "type": [ + "string", + "null" + ], + "enum": [ + "current-page", + "all-pages", + null + ], + "description": "Controls whether dashboard queries execute on the visible page or across all pages." + } + }, + "required": [ + "crossfilterEnabled", + "customText", + "facetFilters", + "refreshInterval", + "runQueriesOn" + ] + }, + "DocumentsV2PatchDraftResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "draftIdentifier": { + "type": "string", + "description": "Identifier of the draft the patch was applied to." + }, + "identifier": { + "type": "string", + "description": "Published document identifier the draft targets." + }, + "name": { + "type": "string", + "description": "Document name." + } + }, + "required": [ + "description", + "draftIdentifier", + "identifier", + "name" + ] + }, + "DocumentsV2CreateDraftBody": { + "allOf": [ + { + "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" + }, + { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Branch the draft is created on. Omit for a draft on the main (unpublished) workspace." + } + }, + "additionalProperties": false + } + ] + }, + "DocumentsV2PatchDraftBody": { + "type": "object", + "properties": { + "containers": { + "$ref": "#/components/schemas/Containers" + }, + "controls": { + "$ref": "#/components/schemas/ControlsPatchExternal" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 254, + "description": "Document name." + }, + "queryPresentations": { + "$ref": "#/components/schemas/QueryPresentationsPatchExternal" + }, + "settings": { + "$ref": "#/components/schemas/SettingsPatchExternal" + }, + "summary": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Optional. Caller-supplied description of what this patch changes, written to the history audit trail. When omitted, the server auto-generates one from the touched sections." + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The document's base model. Immutable and accepted only so a GET response round-trips through PATCH: a value matching the current model is a no-op, and a differing value is rejected \u2014 it cannot re-base the document. Omit it to leave the model untouched." + } + }, + "additionalProperties": false + }, + "DocumentsV2PublishDraftResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "identifier": { + "type": "string", + "description": "Published document identifier." + }, + "name": { + "type": "string", + "description": "Document name." + } + }, + "required": [ + "description", + "identifier", + "name" + ] + }, + "DocumentsV2UpdateIdentifierResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "identifier": { + "type": "string", + "description": "The document identifier after the rename." + }, + "name": { + "type": "string", + "description": "Document name." + } + }, + "required": [ + "description", + "identifier", + "name" + ] + }, + "DocumentsV2UpdateIdentifierBody": { + "type": "object", + "properties": { + "identifier": { + "$ref": "#/components/schemas/DocumentIdentifier" + } + }, + "required": [ + "identifier" + ], + "additionalProperties": false + }, + "EmbedSsoGenerateSessionResponse": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Session ID to use for embedding Omni content" + } + }, + "required": [ + "sessionId" + ] + }, + "EmbedSsoGenerateSessionBody": { + "type": "object", + "properties": { + "externalId": { + "type": "string", + "description": "External identifier for the user (from your system)", + "example": "user-123" + }, + "groups": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional list of non-entity group names to assign to the user. Entity-group membership is managed by the entity parameter.", + "example": [ + "engineering", + "sales" + ] + }, + "name": { + "type": "string", + "description": "Display name for the user", + "example": "John Doe" + }, + "userAttributes": { + "type": "object", + "additionalProperties": {}, + "description": "Optional user attributes for row-level security" + } + }, + "required": [ + "externalId", + "name" + ] + }, + "EvalPromptSetsListResponse": { + "type": "object", + "properties": { + "prompt_sets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalPromptSetListItem" + }, + "description": "Prompt sets matching the query, sorted alphabetically by name." + } + }, + "required": [ + "prompt_sets" + ] + }, + "EvalPromptSetListItem": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description of the prompt set.", + "example": "Regression suite for the orders topic" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the prompt set has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this prompt set is bound to.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "name": { + "type": "string", + "description": "Human-readable name for the prompt set.", + "example": "Orders regression" + }, + "slug": { + "type": "string", + "description": "URL-safe identifier for the prompt set. Unique per `model_id`.", + "example": "orders-regression" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was last updated.", + "example": "2025-01-15T10:00:00.000Z" + }, + "latest_run_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp of the most recent run on this prompt set, if any.", + "example": "2025-01-15T10:05:00.000Z" + }, + "prompt_count": { + "type": "integer", + "description": "Number of prompts in the set.", + "example": 12 + } + }, + "required": [ + "created_at", + "description", + "id", + "is_archived", + "model_id", + "name", + "slug", + "updated_at", + "latest_run_at", + "prompt_count" + ] + }, + "EvalApiError400": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Bad Request: name: Required" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 400 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError401": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Unauthorized: Missing or invalid API key" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 401 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError403": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "AI eval requires at least Querier access on the model" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 403 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError404": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Prompt set not found" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 404 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalPromptSetsCreateResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalPromptSet": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description of the prompt set.", + "example": "Regression suite for the orders topic" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the prompt set has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this prompt set is bound to.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "name": { + "type": "string", + "description": "Human-readable name for the prompt set.", + "example": "Orders regression" + }, + "prompts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalPrompt" + }, + "description": "Prompts that make up the set." + }, + "slug": { + "type": "string", + "description": "URL-safe identifier for the prompt set. Unique per `model_id`.", + "example": "orders-regression" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was last updated.", + "example": "2025-01-15T10:00:00.000Z" + } + }, + "required": [ + "created_at", + "description", + "id", + "is_archived", + "model_id", + "name", + "prompts", + "slug", + "updated_at" + ] + }, + "EvalPrompt": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "expectation": { + "type": [ + "string", + "null" + ], + "description": "The expectation the analysis judge scores the analysis against, or null when none was set.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the prompt.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "prompt_text": { + "type": "string", + "description": "The natural language prompt text the AI is evaluated on.", + "example": "What are the top 5 products by revenue?" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt was last updated.", + "example": "2025-01-15T10:00:00.000Z" + } + }, + "required": [ + "created_at", + "expectation", + "id", + "prompt_text", + "updated_at" + ] + }, + "EvalApiError422": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "A prompt being updated does not belong to this prompt set" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 422 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalPromptSetsCreateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 1024, + "description": "Optional human-readable description of the prompt set. Max 1024 characters.", + "example": "Regression suite for the orders topic" + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this prompt set is bound to.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Human-readable name for the prompt set. 255 characters or fewer.", + "example": "Orders regression" + }, + "prompts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "expectation": { + "type": [ + "string", + "null" + ], + "maxLength": 16000, + "description": "Optional expectation the analysis judge scores the analysis against. Max 16000 characters.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "prompt_text": { + "type": "string", + "minLength": 1, + "maxLength": 8000, + "description": "The natural language prompt text. Max 8000 characters.", + "example": "What are the top 5 products by revenue?" + } + }, + "required": [ + "prompt_text" + ] + }, + "maxItems": 100, + "default": [], + "description": "Initial prompts for the set. Defaults to an empty list. At most 25 prompts." + }, + "slug": { + "type": "string", + "maxLength": 255, + "pattern": "^[a-z][a-z0-9-]*$", + "description": "URL-safe identifier for the prompt set. Must be unique per `model_id` and match `^[a-z][a-z0-9-]*$`. Max 255 characters.", + "example": "orders-regression" + } + }, + "required": [ + "model_id", + "name", + "slug" + ] + }, + "EvalPromptSetsGetResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalPromptSetsUpdateResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalPromptSetsUpdateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 1024, + "description": "New description for the prompt set. Pass `null` to clear. Max 1024 characters." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "New human-readable name for the prompt set. 255 characters or fewer." + }, + "prompts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "expectation": { + "type": [ + "string", + "null" + ], + "maxLength": 16000, + "description": "Optional expectation the analysis judge scores the analysis against. Pass `null` to clear. Max 16000 characters.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Existing prompt id. When provided, updates that prompt; when omitted, a new prompt is created. Prompts not included in this list are removed." + }, + "prompt_text": { + "type": "string", + "minLength": 1, + "maxLength": 8000, + "description": "Updated or new prompt text. Max 8000 characters.", + "example": "What are the top 10 products by revenue this quarter?" + } + }, + "required": [ + "prompt_text" + ] + }, + "maxItems": 100, + "description": "Full desired set of prompts after the update. Prompts omitted from this list are deleted; new prompts (no `id`) are appended in body order. Existing prompts retain their original position \u2014 reordering is not supported on this endpoint. At most 25 prompts total." + } + } + }, + "EvalPromptSetsDeleteResponse": { + "type": "object", + "properties": { + "cancelled_job_count": { + "type": "integer", + "description": "Number of in-flight agentic jobs associated with this prompt set that were cancelled as part of the archive.", + "example": 0 + }, + "is_archived": { + "type": "boolean", + "enum": [ + true + ], + "description": "Always `true` on success \u2014 archives the prompt set." + } + }, + "required": [ + "cancelled_job_count", + "is_archived" + ] + }, + "EvalApiError500": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Archive committed but a run-cancellation failed; retry to complete" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 500 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalPromptSetsUnarchiveResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalRunsListResponse": { + "type": "object", + "properties": { + "runs": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalRunListItem" + }, + "description": "Runs for the prompt set, newest first, filtered to those whose model the caller can access." + } + }, + "required": [ + "runs" + ] + }, + "EvalRunListItem": { + "type": "object", + "properties": { + "branch_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Optional branch ID the run was executed against. Null when run against the main shared model.", + "example": null + }, + "branch_name": { + "type": [ + "string", + "null" + ], + "description": "Display name for the branch, if `branch_id` is set.", + "example": null + }, + "completed_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run reached a terminal state.", + "example": null + }, + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description for the run.", + "example": null + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the run has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this run was executed against.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "prompt_set_id": { + "type": "string", + "format": "uuid", + "description": "The prompt set this run was created from.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "run_number": { + "type": "integer", + "description": "Sequential, per-prompt-set run number.", + "example": 3 + }, + "stats": { + "$ref": "#/components/schemas/EvalRunStats" + }, + "status": { + "type": "string", + "enum": [ + "RUNNING", + "COMPLETE", + "CANCELLED" + ], + "description": "Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly once.", + "example": "RUNNING" + } + }, + "required": [ + "branch_id", + "branch_name", + "completed_at", + "created_at", + "description", + "id", + "is_archived", + "model_id", + "prompt_set_id", + "run_number", + "stats", + "status" + ] + }, + "EvalRunStats": { + "type": "object", + "properties": { + "terminal": { + "type": "integer", + "description": "Number of per-prompt jobs that have reached a terminal state (COMPLETE, FAILED, or CANCELLED).", + "example": 8 + }, + "total": { + "type": "integer", + "description": "Total number of per-prompt jobs in the run.", + "example": 12 + } + }, + "required": [ + "terminal", + "total" + ] + }, + "EvalRunsCreateResponse": { + "type": "object", + "properties": { + "job_count": { + "type": "integer", + "description": "Number of per-prompt agentic jobs created for this run (one per prompt that fanned out successfully). Enqueue onto the work queue happens after creation and is best-effort, so this count reflects jobs created, not necessarily those successfully enqueued.", + "example": 12 + }, + "run": { + "$ref": "#/components/schemas/EvalRunDetail" + } + }, + "required": [ + "job_count", + "run" + ] + }, + "EvalRunDetail": { + "type": "object", + "properties": { + "branch_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Optional branch ID the run was executed against. Null when run against the main shared model.", + "example": null + }, + "branch_name": { + "type": [ + "string", + "null" + ], + "description": "Display name for the branch, if `branch_id` is set.", + "example": null + }, + "completed_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run reached a terminal state.", + "example": null + }, + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description for the run.", + "example": null + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the run has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this run was executed against.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "prompt_set_id": { + "type": "string", + "format": "uuid", + "description": "The prompt set this run was created from.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalRunResult" + }, + "description": "Per-prompt results for this run, ordered by their creation order in the prompt set." + }, + "run_number": { + "type": "integer", + "description": "Sequential, per-prompt-set run number.", + "example": 3 + }, + "status": { + "type": "string", + "enum": [ + "RUNNING", + "COMPLETE", + "CANCELLED" + ], + "description": "Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly once.", + "example": "RUNNING" + } + }, + "required": [ + "branch_id", + "branch_name", + "completed_at", + "created_at", + "description", + "id", + "is_archived", + "model_id", + "prompt_set_id", + "results", + "run_number", + "status" + ], + "description": "The newly created run with its initial results." + }, + "EvalRunResult": { + "type": "object", + "properties": { + "agentic_job": { + "$ref": "#/components/schemas/EvalRunResultAgenticJob" + }, + "ai_timing_ms": { + "type": [ + "integer", + "null" + ], + "description": "Strict main-agent LLM processing time in milliseconds \u2014 the measured model-call duration, excluding tool execution and subagent model calls (those count toward `tool_timing_ms`). Shown as \"AI time\" in the UI. Runs recorded before this was measured fall back to an approximation (`timing_ms` minus tool latency).", + "example": 4121 + }, + "cost": { + "type": [ + "number", + "null" + ], + "description": "Total LLM cost (USD) for this prompt, if available.", + "example": 0.0021 + }, + "error_reason": { + "type": [ + "string", + "null" + ], + "description": "Failure reason string for prompts whose underlying job failed.", + "example": null + }, + "expectation": { + "type": [ + "string", + "null" + ], + "description": "The prompt's expectation as of run creation (snapshotted, so later prompt edits don't change past runs), or null when none was set. The analysis judge scores the analysis against it.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the run result row.", + "example": "aa0e8400-e29b-41d4-a716-446655440005" + }, + "prompt": { + "type": "string", + "description": "The prompt text that was evaluated.", + "example": "What are the top 5 products by revenue?" + }, + "query_count": { + "type": [ + "integer", + "null" + ], + "description": "Number of warehouse queries the underlying job ran. Null for runs executed before this metric was recorded.", + "example": 4 + }, + "query_timing_ms": { + "type": [ + "integer", + "null" + ], + "description": "Total wall-clock time (milliseconds) the underlying job spent running warehouse queries \u2014 a proxy for query execution time. Null for runs executed before this metric was recorded.", + "example": 1800 + }, + "score": { + "type": [ + "number", + "null" + ], + "description": "Numeric judge score for this prompt result, if scoring ran.", + "example": 0.9 + }, + "scoring_cost": { + "type": [ + "number", + "null" + ], + "description": "Total LLM cost (USD) for scoring this prompt result.", + "example": 0.0004 + }, + "timing_ms": { + "type": [ + "integer", + "null" + ], + "description": "Total `/generate` wall-time in milliseconds \u2014 LLM processing plus inner-loop tool execution. `ai_timing_ms` and `tool_timing_ms` split this; warehouse query time is separate (`query_timing_ms`).", + "example": 4321 + }, + "tool_timing_ms": { + "type": [ + "integer", + "null" + ], + "description": "Inner-loop tool latency in milliseconds \u2014 time spent running tools the model invoked (model and field-value lookups, query planning), excluding the warehouse query itself (`query_timing_ms`). Null for runs recorded before per-tool latency was tracked.", + "example": 200 + } + }, + "required": [ + "agentic_job", + "ai_timing_ms", + "cost", + "error_reason", + "expectation", + "id", + "prompt", + "query_count", + "query_timing_ms", + "score", + "scoring_cost", + "timing_ms", + "tool_timing_ms" + ] + }, + "EvalRunResultAgenticJob": { + "type": "object", + "properties": { + "conversation_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Conversation the agentic job belongs to.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Agentic job identifier.", + "example": "990e8400-e29b-41d4-a716-446655440004" + }, + "state": { + "type": "string", + "enum": [ + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED" + ], + "description": "Current state of the agentic job that ran this prompt.", + "example": "COMPLETE" + } + }, + "required": [ + "conversation_id", + "id", + "state" + ] + }, + "EvalApiError429": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Too many active runs; wait for an in-flight run to finish" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 429 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError503": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "AI eval is paused for this organization" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 503 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalRunsCreateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 1024, + "description": "Optional human-readable description for the run. Pass `null` to clear (or omit). Max 1024 characters.", + "example": "Re-running after switching to gpt-4o for query generation" + }, + "prompt_set_id": { + "type": "string", + "format": "uuid", + "description": "The prompt set to execute.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "run_config": { + "type": "object", + "properties": { + "branch_id": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID to run against. Must be a branch of the prompt set's model.", + "example": "440e8400-e29b-41d4-a716-446655440006" + } + }, + "description": "Per-run configuration. Optional \u2014 omit if no overrides." + } + }, + "required": [ + "prompt_set_id" + ] + }, + "EvalRunsGetResponse": { + "type": "object", + "properties": { + "run": { + "$ref": "#/components/schemas/EvalRunDetail" + } + }, + "required": [ + "run" + ] + }, + "EvalRunsDeleteResponse": { + "type": "object", + "properties": { + "is_archived": { + "type": "boolean", + "enum": [ + true + ], + "description": "Always `true` on success \u2014 the run has been archived." + } + }, + "required": [ + "is_archived" + ] + }, + "EvalRunsCancelResponse": { + "type": "object", + "properties": { + "cancelled": { + "type": "integer", + "description": "Number of per-prompt agentic jobs that were cancelled by this request.", + "example": 4 + }, + "run": { + "$ref": "#/components/schemas/EvalRunDetail" + }, + "total": { + "type": "integer", + "description": "Total number of per-prompt jobs in the run.", + "example": 12 + } + }, + "required": [ + "cancelled", + "run", + "total" + ] + }, + "EvalRunsUnarchiveResponse": { + "type": "object", + "properties": { + "is_archived": { + "type": "boolean", + "enum": [ + false + ], + "description": "Always `false` on success \u2014 the run has been unarchived." + } + }, + "required": [ + "is_archived" + ] + }, + "FoldersListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "_count": { + "type": "object", + "properties": { + "documents": { + "type": "number", + "description": "Number of documents in the folder" + }, + "favorites": { + "type": "number", + "description": "Number of users who have favorited this folder" + } + }, + "required": [ + "documents", + "favorites" + ], + "description": "Count statistics for the folder" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique folder identifier" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels associated with the folder" + }, + "name": { + "type": "string", + "description": "Name of the folder", + "example": "My Reports" + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the folder owner" + }, + "path": { + "type": "string", + "description": "Full path to the folder", + "example": "/shared/reports/my-reports" + }, + "url": { + "type": "string", + "description": "URL to view the folder in the Omni UI.", + "example": "https://org.omni.co/f/my-reports" + } + }, + "required": [ + "id", + "name", + "ownerId", + "path", + "url" + ] + }, + "description": "List of folders" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "FoldersCreateResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "ID of the created folder" + }, + "name": { + "type": "string", + "description": "Name of the created folder" + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the folder owner" + }, + "path": { + "type": "string", + "description": "Full path to the folder" + }, + "scope": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Share scope of the folder" + } + }, + "required": [ + "id", + "name", + "ownerId", + "path", + "scope" + ] + }, + "FoldersCreateBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Name of the folder to create", + "example": "My New Folder" + }, + "parentFolderId": { + "type": "string", + "format": "uuid", + "description": "Parent folder ID (omit to create at root level)" + }, + "scope": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Share scope for the folder" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID to create the folder as (for org-scoped API keys only)" + } + }, + "required": [ + "name" + ] + }, + "FoldersDeleteResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the folder was deleted successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersUpdateResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Folder ID" + }, + "name": { + "type": "string", + "description": "Updated folder name" + }, + "path": { + "type": "string", + "description": "Updated URL path segment for the folder (the folder's own segment only)" + } + }, + "required": [ + "id", + "name", + "path" + ] + }, + "FoldersUpdateBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "New display name for the folder", + "example": "Q1 Reports" + }, + "path": { + "type": "string", + "minLength": 1, + "pattern": "^[a-zA-Z0-9-]+$", + "description": "New URL path segment for the folder (alphanumeric and dashes only). This is only the folder's own segment, not the full hierarchical path.", + "example": "q1-reports" + }, + "resolvePathConflict": { + "type": "boolean", + "default": false, + "description": "When true, automatically resolves path collisions with existing folders by appending a numeric suffix (e.g., my-path-1). When false (default), returns 409 Conflict if the path is already taken. Does not apply to reserved paths, which are always rejected with 400." + } + } + }, + "FoldersGetPermissionsResponse": { + "type": "object", + "properties": { + "permits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "description": "Whether access boost is enabled for this permit" + }, + "role": { + "type": "string", + "description": "Content role (e.g., VIEWER, EDITOR, MANAGER)", + "example": "VIEWER" + }, + "userGroupId": { + "type": "string", + "description": "User group ID if this is a group permit" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID if this is a user permit" + } + }, + "required": [ + "role" + ] + }, + "description": "List of permission permits for the folder" + } + }, + "required": [ + "permits" + ] + }, + "FoldersAddPermissionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the permissions were added successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersAddPermissionsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "default": false, + "description": "Whether to grant access boost" + }, + "role": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "Content role to assign (VIEWER, EDITOR, or MANAGER)", + "example": "VIEWER" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to grant permission to" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to grant permission to" + } + }, + "required": [ + "role" + ], + "additionalProperties": false + }, + "FoldersUpdatePermissionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the permissions were updated successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersUpdatePermissionsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "description": "Whether to grant access boost" + }, + "role": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "New content role to assign" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to update permissions for" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to update permissions for" + } + }, + "additionalProperties": false + }, + "FoldersRevokePermissionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the permissions were revoked successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersRevokePermissionsBody": { + "type": "object", + "properties": { + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to revoke permissions from" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to revoke permissions from" + } + }, + "additionalProperties": false + }, + "LabelsListResponse": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "description": "List of labels" + } + }, + "required": [ + "labels" + ] + }, + "LabelsCreateResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsCreateBody": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "default": null, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "default": null, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "default": false, + "description": "Show label on homepage. Requires admin permissions." + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 25, + "description": "Label name", + "example": "important" + }, + "verified": { + "type": "boolean", + "default": false, + "description": "Mark as verified label. Requires admin permissions." + } + }, + "required": [ + "name" + ] + }, + "LabelsGetResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsUpdateResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsUpdateBody": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Show label on homepage. Requires admin permissions to modify." + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 25, + "description": "Label name", + "example": "important" + }, + "verified": { + "type": "boolean", + "description": "Mark as verified label. Requires admin permissions to modify." + } + } + }, + "ModelSuggestionsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ModelSuggestion" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "ModelSuggestion": { + "type": "object", + "properties": { + "aiModifiedAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of the last AI write (create or AI update). Unaffected by dismiss/restore." + }, + "category": { + "type": "string", + "description": "Suggestion category, e.g. `missing_context`.", + "example": "missing_context" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of when the suggestion was created." + }, + "evidence": { + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/components/schemas/SuggestionEvidenceItem" + }, + "description": "Source evidence for the suggestion. Null for rows created before evidence was tracked; `[]` when none was cited." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the suggestion." + }, + "ignoreReason": { + "type": [ + "string", + "null" + ], + "description": "Optional free-text reason recorded when the suggestion was dismissed." + }, + "ignoredAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "ISO 8601 timestamp of dismissal, or null if active." + }, + "ignoredBy": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "User id that dismissed the suggestion, or null if active." + }, + "priority": { + "type": "integer", + "minimum": 1, + "maximum": 10, + "description": "Priority from 1 (highest) to 10 (lowest).", + "example": 1 + }, + "proposedChanges": { + "$ref": "#/components/schemas/SuggestionProposedChanges" + }, + "rationale": { + "type": "string", + "description": "Explanation of why the suggestion was made." + }, + "title": { + "type": "string", + "description": "Short human-readable title." + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of the last write of any kind, including dismiss/restore." + } + }, + "required": [ + "aiModifiedAt", + "category", + "createdAt", + "evidence", + "id", + "ignoreReason", + "ignoredAt", + "ignoredBy", + "priority", + "proposedChanges", + "rationale", + "title", + "updatedAt" + ] + }, + "SuggestionEvidenceItem": { + "type": "object", + "properties": { + "capturedAt": { + "type": "string", + "description": "ISO 8601 timestamp of when the evidence was captured." + }, + "chatAiSessionId": { + "type": "string", + "format": "uuid", + "description": "Chat session that motivated the suggestion." + }, + "type": { + "type": "string", + "enum": [ + "ai_chat" + ] + } + }, + "required": [ + "capturedAt", + "chatAiSessionId", + "type" + ] + }, + "SuggestionProposedChanges": { + "type": "object", + "properties": { + "edits": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SuggestionContextEdit" + } + }, + "kind": { + "type": "string", + "enum": [ + "context_edits" + ] + } + }, + "required": [ + "edits", + "kind" + ], + "description": "The change(s) the suggestion would apply to the model." + }, + "SuggestionContextEdit": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "The model field being edited (e.g. `ai_context`).", + "example": "ai_context" + }, + "target": { + "type": "string", + "description": "Dot-path identifying what the edit applies to, e.g. `views.orders.fields.status`.", + "example": "views.orders" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "The proposed value for the field." + } + }, + "required": [ + "field", + "target", + "value" + ] + }, + "ScheduleSuggestionsResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "The schedule (trigger) id." + }, + "sharedModelId": { + "type": "string", + "format": "uuid", + "description": "The shared model the schedule generates suggestions for." + }, + "status": { + "type": "string", + "enum": [ + "enabled" + ] + }, + "timezone": { + "type": "string", + "description": "IANA timezone the schedule runs in.", + "example": "America/New_York" + } + }, + "required": [ + "id", + "sharedModelId", + "status", + "timezone" + ] + }, + "ScheduleSuggestionsBody": { + "type": "object", + "properties": { + "timezone": { + "type": "string", + "default": "UTC", + "description": "IANA timezone the schedule fires in (e.g. `America/New_York`). Generation currently runs once daily at ~2 AM in this timezone. Defaults to `UTC`.", + "example": "America/New_York" + } + }, + "additionalProperties": false + }, + "IgnoreSuggestionBody": { + "type": "object", + "properties": { + "reason": { + "type": "string", + "maxLength": 4000, + "description": "Optional free-text reason for dismissing the suggestion.", + "example": "Already covered by an existing field description." + } + }, + "additionalProperties": false + }, + "ModelsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseModelId": { + "type": [ + "string", + "null" + ], + "description": "Base model ID for branch/extension models" + }, + "branches": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Branch ID" + }, + "name": { + "type": "string", + "description": "Branch name" + } + }, + "required": [ + "id", + "name" + ] + }, + "description": "Active branches (if include=activeBranches)" + }, + "connectionId": { + "type": [ + "string", + "null" + ], + "description": "Connection ID" + }, + "createdAt": { + "type": "string", + "description": "Creation timestamp" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Deletion timestamp" + }, + "id": { + "type": "string", + "description": "Model ID" + }, + "modelKind": { + "type": [ + "string", + "null" + ], + "description": "Model kind" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Model name" + }, + "updatedAt": { + "type": "string", + "description": "Last update timestamp" + } + }, + "required": [ + "baseModelId", + "connectionId", + "createdAt", + "deletedAt", + "id", + "modelKind", + "name", + "updatedAt" + ] + }, + "description": "List of model records" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "CreateModelSchemaBase": { + "type": "object", + "properties": { + "accessGrants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "accessBoostable": { + "type": "boolean" + }, + "allowedValues": { + "type": "array", + "items": { + "type": "string" + } + }, + "codeComments": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "ignored": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "userAttribute": { + "type": "string" + } + }, + "required": [ + "accessBoostable", + "name" + ] + }, + "description": "Access grants for the model" + }, + "allowAsWorkbookBase": { + "type": "boolean", + "description": "Allow this model as a workbook base" + }, + "baseModelId": { + "type": "string", + "description": "Base model ID for extension or branch models" + }, + "connectionId": { + "type": "string", + "description": "Connection ID for the model" + }, + "modelKind": { + "anyOf": [ + { + "type": "string", + "enum": [ + "SCHEMA" + ] + }, + { + "type": "string", + "enum": [ + "SHARED" + ] + }, + { + "type": "string", + "enum": [ + "SHARED_EXTENSION" + ] + }, + { + "type": "string", + "enum": [ + "BRANCH" + ] + } + ], + "default": "SCHEMA", + "description": "Kind of model to create" + }, + "modelName": { + "type": "string", + "description": "Name for the model" + }, + "usesIsolatedBranches": { + "type": "boolean", + "description": "For SHARED_EXTENSION models, controls if branches are shown on extension model page instead of parent shared model" + } + }, + "required": [ + "connectionId" + ] + }, + "ModelsUpdateResponse": { + "type": "object", + "properties": { + "model": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Model ID" + }, + "name": { + "type": "string", + "description": "Updated model name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Updated model details" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + } + }, + "required": [ + "model", + "success" + ] + }, + "ModelsUpdateBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "New name for the model", + "example": "My Renamed Model" + } + }, + "required": [ + "name" + ] + }, + "JobsGetStatusResponse": { + "type": "object", + "properties": { + "job_id": { + "type": "string", + "description": "The job ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "job_type": { + "type": "string", + "description": "The type of job (e.g., REFRESH_SCHEMA)", + "example": "REFRESH_SCHEMA" + }, + "status": { + "type": "string", + "enum": [ + "IN_PROGRESS", + "COMPLETED", + "FAILED" + ], + "description": "Current status of the job", + "example": "COMPLETED" + } + }, + "required": [ + "job_id", + "job_type", + "status" + ] + }, + "ModelsGetSchemasResponse": { + "type": "object", + "properties": { + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Sorted list of all available schema names (catalog-scoped if applicable, e.g. warehouse.reporting)" + } + }, + "required": [ + "schemas" + ] + }, + "ModelsGetViewResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "views": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "View description" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Field name" + }, + "type": { + "type": "string", + "enum": [ + "dimension", + "measure", + "filter" + ], + "description": "Field type" + } + }, + "required": [ + "name", + "type" + ] + }, + "description": "Fields in the view" + }, + "hidden": { + "type": "boolean", + "description": "Whether the view is hidden" + }, + "label": { + "type": "string", + "description": "View label" + }, + "name": { + "type": "string", + "description": "View name" + } + }, + "required": [ + "fields", + "name" + ] + }, + "description": "List of views" + } + }, + "required": [ + "success", + "views" + ] + }, + "ModelsUpdateViewBody": { + "type": "object", + "properties": { + "aiContext": { + "type": "string", + "description": "AI context for the view" + }, + "description": { + "type": "string", + "description": "View description" + }, + "format": { + "type": "string", + "description": "View format" + }, + "hidden": { + "type": "boolean", + "description": "Whether the view is hidden" + }, + "label": { + "type": "string", + "description": "View label" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the view" + } + } + }, + "ModelsUpdateFieldBody": { + "type": "object", + "properties": { + "aiContext": { + "type": "string", + "description": "AI context for the field" + }, + "allValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Deprecated: use sampleValues instead" + }, + "binBoundaries": { + "type": "array", + "items": { + "type": "number" + }, + "description": "Bin boundaries for binned fields" + }, + "binLabels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels for bins" + }, + "description": { + "type": "string", + "description": "Field description" + }, + "drillFields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Drill-down fields" + }, + "elseValue": { + "type": "string", + "description": "Else value for grouped fields" + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "description": "Filters for the field" + }, + "format": { + "type": "string", + "description": "Field format" + }, + "groupFilters": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Group filters" + }, + "groupLabel": { + "type": "string", + "description": "Group label" + }, + "groupNames": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Group names" + }, + "hidden": { + "type": "boolean", + "description": "Whether the field is hidden" + }, + "ignored": { + "type": "boolean", + "description": "Whether the field is ignored" + }, + "isCalc": { + "type": "boolean", + "description": "Whether this is a calculation field" + }, + "label": { + "type": "string", + "description": "Field label" + }, + "newFieldName": { + "type": "string", + "description": "New field name (for rename)" + }, + "newViewName": { + "type": "string", + "description": "New view name (for move)" + }, + "sampleValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Sample values for the field" + }, + "sql": { + "type": "string", + "description": "SQL expression for the field" + }, + "synonyms": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Synonyms for the field" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the field" + }, + "topicContext": { + "type": "string", + "description": "Topic context for the field" + } + } + }, + "ModelsListTopicsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "topics": { + "type": "array", + "items": { + "type": "object", + "properties": { + "base_view_name": { + "type": "string", + "description": "Base view name for the topic" + }, + "description": { + "type": "string", + "description": "Topic description" + }, + "group_label": { + "type": "string", + "description": "Group label" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "name": { + "type": "string", + "description": "Topic name" + } + }, + "required": [ + "base_view_name", + "name" + ] + }, + "description": "List of topics" + } + }, + "required": [ + "success", + "topics" + ] + }, + "ModelsGetTopicResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "topic": { + "type": "object", + "properties": { + "base_view_name": { + "type": "string", + "description": "Base view name for the topic" + }, + "description": { + "type": "string", + "description": "Topic description" + }, + "group_label": { + "type": "string", + "description": "Group label" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "name": { + "type": "string", + "description": "Topic name" + }, + "relationships": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Relationships for the topic" + }, + "views": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Views available in the topic" + } + }, + "required": [ + "base_view_name", + "name", + "relationships", + "views" + ], + "description": "Topic details with relationships and views" + } + }, + "required": [ + "success", + "topic" + ] + }, + "ModelsUpdateTopicBody": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Topic description" + }, + "groupLabel": { + "type": "string", + "description": "Group label for the topic" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "newTopicName": { + "type": "string", + "description": "New topic name (for rename)" + } + } + }, + "ModelsCreateFieldBody": { + "type": "object", + "properties": { + "aggregateType": { + "type": "string", + "enum": [ + "AVERAGE", + "COUNT", + "COUNT_DISTINCT", + "LIST", + "MAX", + "MIN", + "SUM", + "MEDIAN", + "PERCENTILE", + "AVERAGE_DISTINCT_ON", + "SUM_DISTINCT_ON", + "MEDIAN_DISTINCT_ON", + "PERCENTILE_DISTINCT_ON", + "SEMANTIC_VIEW_AGG" + ], + "description": "Aggregate type for measures. Setting this property promotes the field to a measure (written under `measures:`); omit it to create a dimension (written under `dimensions:`). Values must be uppercase canonical names.", + "example": "SUM" + }, + "aiContext": { + "type": "string", + "description": "AI context for the field" + }, + "description": { + "type": "string", + "description": "Field description" + }, + "fieldName": { + "type": "string", + "description": "Field name", + "example": "total_revenue" + }, + "format": { + "type": "string", + "description": "Field format" + }, + "hidden": { + "type": "boolean", + "description": "Whether the field is hidden" + }, + "label": { + "type": "string", + "description": "Field label" + }, + "sql": { + "type": "string", + "description": "SQL expression for the field" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the field" + }, + "topicContext": { + "type": "string", + "description": "Topic context for topic-scoped fields" + }, + "viewName": { + "type": "string", + "description": "View to add the field to", + "example": "orders" + } + }, + "required": [ + "fieldName", + "viewName" + ], + "additionalProperties": false + }, + "ModelsRefreshResponse": { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "description": "Job ID for the refresh operation" + }, + "modelId": { + "type": "string", + "description": "Model ID being refreshed" + }, + "status": { + "type": "string", + "enum": [ + "running", + "completed", + "failed" + ], + "description": "Current status of the refresh" + } + }, + "required": [ + "jobId", + "modelId", + "status" + ] + }, + "ModelsValidateResponse": { + "type": "object", + "properties": { + "issues": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "Field name with the issue" + }, + "message": { + "type": "string", + "description": "Validation issue message" + }, + "severity": { + "type": "string", + "enum": [ + "error", + "warning" + ], + "description": "Issue severity" + }, + "view": { + "type": "string", + "description": "View name with the issue" + } + }, + "required": [ + "message", + "severity" + ] + }, + "description": "List of validation issues" + }, + "valid": { + "type": "boolean", + "description": "Whether the model is valid" + } + }, + "required": [ + "issues", + "valid" + ] + }, + "ModelsMigrateBody": { + "type": "object", + "properties": { + "branchName": { + "type": "string", + "description": "Branch name for the target model" + }, + "commitMessage": { + "type": "string", + "description": "Commit message for git sync" + }, + "deleteViewsAndTopicsMissingFromSource": { + "type": "boolean", + "default": true, + "description": "When true (default), views and topics in the target model that are missing from the migrated source are deleted (the source is treated as the complete model). When false, they are kept (inherited) instead \u2014 useful when the source git ref may be missing objects that exist in omni but not in git, e.g. a newly synced schema." + }, + "gitRef": { + "type": "string", + "description": "Git reference" + }, + "targetModelId": { + "type": "string", + "format": "uuid", + "description": "Target model ID to migrate to" + } + }, + "required": [ + "targetModelId" + ] + }, + "ModelsDbtExposuresResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtExposureWithMeta" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "DbtExposureWithMeta": { + "type": "object", + "properties": { + "dashboard_identifier": { + "type": "string", + "description": "Identifier of the dashboard that generated this exposure" + }, + "deduplication_name": { + "type": "string", + "description": "A unique name for this exposure. Use this instead of exposure.name to avoid duplicate names, or use it as a fallback when exposure.name collides with another exposure." + }, + "exposure": { + "$ref": "#/components/schemas/DbtExposure" + } + }, + "required": [ + "dashboard_identifier", + "deduplication_name", + "exposure" + ] + }, + "DbtExposure": { + "type": "object", + "properties": { + "depends_on": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of dbt model references (e.g. ref('model_name'))", + "example": [ + "ref('orders')", + "ref('customers')" + ] + }, + "label": { + "type": "string", + "description": "Original dashboard name" + }, + "name": { + "type": "string", + "description": "Sanitized exposure name. May contain duplicates across exposures; use deduplication_name for a guaranteed-unique alternative.", + "example": "my_dashboard" + }, + "owner": { + "$ref": "#/components/schemas/DbtExposureOwner" + }, + "type": { + "type": "string", + "enum": [ + "dashboard", + "notebook", + "analysis", + "ml", + "application" + ], + "description": "Type of the exposure", + "example": "dashboard" + }, + "url": { + "type": "string", + "description": "URL of the dashboard" + } + }, + "required": [ + "depends_on", + "name", + "owner", + "type" + ], + "description": "The dbt exposure for this dashboard." + }, + "DbtExposureOwner": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email of the dashboard owner" + }, + "name": { + "type": "string", + "description": "Name of the dashboard owner" + } + }, + "required": [ + "email", + "name" + ] + }, + "ModelsBranchDbtBody": { + "type": "object", + "properties": { + "dbt_environment_id": { + "type": "string", + "format": "uuid", + "description": "ID of the dbt environment to activate on this branch", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "dbt_git_branch": { + "type": "string", + "description": "Git branch to associate with the dbt environment", + "example": "feature/new-metrics" + } + }, + "required": [ + "dbt_environment_id" + ] + }, + "JobCreatedResponse": { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "description": "ID of the created job. Poll GET /api/v1/jobs/{jobId}/status for its status.", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "jobId" + ] + }, + "ModelsMergeBranchResponse": { + "type": "object", + "properties": { + "failed_drafts_count": { + "type": "number", + "description": "Number of drafts that failed to publish" + }, + "git_synced": { + "type": "boolean", + "description": "Whether git was synced" + }, + "published_drafts_count": { + "type": "number", + "description": "Number of drafts published" + }, + "success": { + "type": "boolean", + "description": "Whether the merge succeeded" + } + }, + "required": [ + "failed_drafts_count", + "git_synced", + "published_drafts_count", + "success" + ] + }, + "ModelsMergeBranchBody": { + "type": "object", + "properties": { + "commit_message": { + "type": "string", + "description": "Custom commit message for git sync" + }, + "delete_branch": { + "type": "boolean", + "default": false, + "description": "Delete the branch after merging" + }, + "force_override_git_settings": { + "type": "boolean", + "default": false, + "description": "Override PR-required or git-follower settings" + }, + "publish_drafts": { + "type": "boolean", + "default": true, + "description": "Publish branch-attached drafts" + } + } + }, + "ModelsCommitResponse": { + "type": "object", + "properties": { + "did_sync": { + "type": "boolean", + "description": "Whether a sync operation was performed against git" + }, + "git_sha": { + "type": [ + "string", + "null" + ], + "description": "The git SHA of the commit that was pushed (null if no commit was needed)" + }, + "in_sync": { + "type": "boolean", + "description": "Whether the branch is in sync with git after the operation" + }, + "pr_url": { + "type": [ + "string", + "null" + ], + "description": "The URL of the pull request (or PR creation page for newly-created PRs). May be null when the underlying git provider is not recognized." + } + }, + "required": [ + "did_sync", + "git_sha", + "in_sync", + "pr_url" + ] + }, + "ModelsCommitBody": { + "type": "object", + "properties": { + "allow_branch_exists": { + "type": "boolean", + "default": true, + "description": "If true (default), the commit succeeds whether the git branch already exists or not. If false, the request fails when the git branch already exists \u2014 use this to ensure only new pull requests are created. Cannot be false when require_branch_exists is true.", + "example": true + }, + "branch_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the branch to commit.", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "commit_message": { + "type": "string", + "minLength": 1, + "description": "Commit message for the git commit.", + "example": "Add new orders view" + }, + "require_branch_exists": { + "type": "boolean", + "default": false, + "description": "If true, the request fails when the git branch does not already exist \u2014 use this to ensure only existing pull requests are updated. Defaults to false. Cannot be true when allow_branch_exists is false.", + "example": false + } + }, + "required": [ + "branch_id", + "commit_message" + ] + }, + "ModelsCacheResetResponse": { + "type": "object", + "properties": { + "cache_reset": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "Creation timestamp" + }, + "model_id": { + "type": "string", + "description": "Model ID" + }, + "policy_name": { + "type": "string", + "description": "Cache policy name" + }, + "reset_at": { + "type": [ + "string", + "null" + ], + "description": "Reset timestamp" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "Last update timestamp" + } + }, + "required": [ + "created_at", + "model_id", + "policy_name", + "reset_at", + "updated_at" + ], + "description": "Cache reset details" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + } + }, + "required": [ + "cache_reset", + "success" + ] + }, + "ModelsCacheResetBody": { + "type": "object", + "properties": { + "resetAt": { + "type": "string", + "description": "ISO-8601 timestamp for when to reset the cache", + "example": "2024-01-15T12:00:00Z" + } + } + }, + "ModelsGitGetResponse": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" + }, + "baseBranch": { + "type": "string", + "description": "The target branch for Omni pull requests", + "example": "main" + }, + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false + }, + "cloneUrl": { + "type": "string", + "description": "Clone URL of the git repository (SSH or HTTPS)", + "example": "git@github.com:org/repo.git" + }, + "gitFollower": { + "type": "boolean", + "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", + "example": false + }, + "gitServiceProvider": { + "type": "string", + "description": "The git provider type", + "example": "github" + }, + "modelPath": { + "type": [ + "string", + "null" + ], + "description": "Path to model files in the repository", + "example": "omni/my_model" + }, + "publicKey": { + "type": [ + "string", + "null" + ], + "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", + "example": "ssh-ed25519 AAAA..." + }, + "requirePullRequest": { + "type": "string", + "enum": [ + "always", + "users-only", + "never" + ], + "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", + "example": "users-only" + }, + "sshUrl": { + "type": "string", + "deprecated": true, + "description": "Deprecated \u2014 use cloneUrl. Clone URL of the git repository." + }, + "webUrl": { + "type": [ + "string", + "null" + ], + "description": "Custom web URL for the git repository, or null if not set", + "example": "https://github.com/org/repo" + }, + "webhookSecret": { + "type": "string", + "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" + }, + "webhookUrl": { + "type": "string", + "description": "Webhook URL to configure in your git provider", + "example": "https://app.omni.co/api/webhooks/model/..." + } + }, + "required": [ + "authMethod", + "baseBranch", + "branchPerPullRequest", + "cloneUrl", + "gitFollower", + "gitServiceProvider", + "modelPath", + "publicKey", + "requirePullRequest", + "sshUrl", + "webUrl", + "webhookUrl" + ] + }, + "ModelsGitCreateResponse": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" + }, + "baseBranch": { + "type": "string", + "description": "The target branch for Omni pull requests", + "example": "main" + }, + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false + }, + "cloneUrl": { + "type": "string", + "description": "Clone URL of the git repository (SSH or HTTPS)", + "example": "git@github.com:org/repo.git" + }, + "gitFollower": { + "type": "boolean", + "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", + "example": false + }, + "gitServiceProvider": { + "type": "string", + "description": "The git provider type", + "example": "github" + }, + "modelPath": { + "type": [ + "string", + "null" + ], + "description": "Path to model files in the repository", + "example": "omni/my_model" + }, + "publicKey": { + "type": [ + "string", + "null" + ], + "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", + "example": "ssh-ed25519 AAAA..." + }, + "requirePullRequest": { + "type": "string", + "enum": [ + "always", + "users-only", + "never" + ], + "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", + "example": "users-only" + }, + "sshUrl": { + "type": "string", + "deprecated": true, + "description": "Deprecated \u2014 use cloneUrl. Clone URL of the git repository." + }, + "webUrl": { + "type": [ + "string", + "null" + ], + "description": "Custom web URL for the git repository, or null if not set", + "example": "https://github.com/org/repo" + }, + "webhookSecret": { + "type": "string", + "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" + }, + "webhookUrl": { + "type": "string", + "description": "Webhook URL to configure in your git provider", + "example": "https://app.omni.co/api/webhooks/model/..." + } + }, + "required": [ + "authMethod", + "baseBranch", + "branchPerPullRequest", + "cloneUrl", + "gitFollower", + "gitServiceProvider", + "modelPath", + "publicKey", + "requirePullRequest", + "sshUrl", + "webUrl", + "webhookUrl" + ] + }, + "ModelsGitCreateBody": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" + ], + "default": "ssh", + "description": "Authentication method. \"ssh\" for deploy key (default), \"https_token\" for deploy token/PAT.", + "example": "ssh" + }, + "baseBranch": { + "type": "string", + "default": "main", + "description": "The target branch for Omni pull requests. Defaults to \"main\"", + "example": "main" + }, + "branchPerPullRequest": { + "type": "boolean", + "default": false, + "description": "If true, all pull requests will create a branch in Omni. Defaults to false", + "example": false + }, + "cloneUrl": { + "type": "string", + "minLength": 1, + "description": "Clone URL of the git repository. SSH (git@...) for deploy key auth, HTTPS (https://...) for token auth.", + "example": "git@github.com:org/repo.git" + }, + "gitFollower": { + "type": "boolean", + "default": false, + "description": "If true, the shared model will be read-only. Defaults to false", + "example": false + }, + "gitServiceProvider": { + "type": "string", + "enum": [ + "github", + "gitlab", + "azure_devops", + "bitbucket", + "bitbucket_datacenter", + "auto" + ], + "default": "auto", + "description": "The git provider type. Use \"auto\" for automatic detection. Defaults to \"auto\"", + "example": "auto" + }, + "modelPath": { + "type": "string", + "description": "Path to model files in the repository. Defaults to omni/. Use a plain name (e.g., \"my_model\") for omni/my_model, or a leading slash for a custom path (e.g., \"/bi/models/sales\")", + "example": "my_model" + }, + "requirePullRequest": { + "type": "string", + "enum": [ + "always", + "users-only", + "never" + ], + "default": "never", + "description": "Controls when pull requests are required. Defaults to \"never\"", + "example": "never" + }, + "sshUrl": { + "type": "string", + "minLength": 1, + "description": "Deprecated \u2014 use cloneUrl. Clone URL of the git repository.", + "example": "git@github.com:org/repo.git", + "deprecated": true + }, + "token": { + "type": "string", + "maxLength": 1000, + "pattern": "^[a-zA-Z0-9_\\-.]+$", + "description": "HTTPS token for authentication (deploy token value, PAT, etc.). Required when authMethod is \"https_token\"." + }, + "webUrl": { + "type": "string", + "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", + "example": "https://github.com/org/repo" + } + } + }, + "ModelsGitUpdateResponse": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" + }, + "baseBranch": { + "type": "string", + "description": "The target branch for Omni pull requests", + "example": "main" + }, + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false + }, + "cloneUrl": { + "type": "string", + "description": "Clone URL of the git repository (SSH or HTTPS)", + "example": "git@github.com:org/repo.git" + }, + "gitFollower": { + "type": "boolean", + "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", + "example": false + }, + "gitServiceProvider": { + "type": "string", + "description": "The git provider type", + "example": "github" + }, + "modelPath": { + "type": [ + "string", + "null" + ], + "description": "Path to model files in the repository", + "example": "omni/my_model" + }, + "publicKey": { + "type": [ + "string", + "null" + ], + "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", + "example": "ssh-ed25519 AAAA..." + }, + "requirePullRequest": { + "type": "string", + "enum": [ + "always", + "users-only", + "never" + ], + "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", + "example": "users-only" + }, + "sshUrl": { + "type": "string", + "deprecated": true, + "description": "Deprecated \u2014 use cloneUrl. Clone URL of the git repository." + }, + "webUrl": { + "type": [ + "string", + "null" + ], + "description": "Custom web URL for the git repository, or null if not set", + "example": "https://github.com/org/repo" + }, + "webhookSecret": { + "type": "string", + "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" + }, + "webhookUrl": { + "type": "string", + "description": "Webhook URL to configure in your git provider", + "example": "https://app.omni.co/api/webhooks/model/..." + } + }, + "required": [ + "authMethod", + "baseBranch", + "branchPerPullRequest", + "cloneUrl", + "gitFollower", + "gitServiceProvider", + "modelPath", + "publicKey", + "requirePullRequest", + "sshUrl", + "webUrl", + "webhookUrl" + ] + }, + "ModelsGitUpdateBody": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method to change to.", + "example": "ssh" + }, + "baseBranch": { + "type": "string", + "description": "The target branch for Omni pull requests", + "example": "main" + }, + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni", + "example": false + }, + "cloneUrl": { + "type": "string", + "minLength": 1, + "description": "Clone URL of the git repository (SSH or HTTPS).", + "example": "git@github.com:org/repo.git" + }, + "gitFollower": { + "type": "boolean", + "description": "If true, the shared model will be read-only", + "example": false + }, + "gitServiceProvider": { + "type": "string", + "enum": [ + "github", + "gitlab", + "azure_devops", + "bitbucket", + "bitbucket_datacenter", + "auto" + ], + "description": "The git provider type", + "example": "github" + }, + "modelPath": { + "type": "string", + "description": "Path to model files in the repository", + "example": "my_model" + }, + "requirePullRequest": { + "type": "string", + "enum": [ + "always", + "users-only", + "never" + ], + "description": "Controls when pull requests are required", + "example": "users-only" + }, + "sshUrl": { + "type": "string", + "minLength": 1, + "description": "Deprecated \u2014 use cloneUrl. Clone URL of the git repository.", + "example": "git@github.com:org/repo.git", + "deprecated": true + }, + "token": { + "type": "string", + "maxLength": 1000, + "pattern": "^[a-zA-Z0-9_\\-.]+$", + "description": "HTTPS token for authentication (deploy token value, PAT, etc.)." + }, + "webUrl": { + "type": "string", + "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", + "example": "https://github.com/org/repo" + } + } + }, + "ModelsGitDeleteResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "Git repository unlinked successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ] + }, + "ModelsGitSyncResponse": { + "type": "object", + "properties": { + "didSync": { + "type": "boolean", + "description": "Whether a sync operation was performed" + }, + "gitSha": { + "type": [ + "string", + "null" + ], + "description": "The git SHA after the sync operation" + }, + "inSync": { + "type": "boolean", + "description": "Whether the model is currently in sync with git" + }, + "message": { + "type": "string", + "description": "Human-readable message about the sync status" + } + }, + "required": [ + "didSync", + "gitSha", + "inSync", + "message" + ] + }, + "ModelsGitSyncBody": { + "type": "object", + "properties": { + "commitMessage": { + "type": "string", + "description": "Optional commit message for the git sync operation", + "example": "Update model schema" + } + } + }, + "ModelsContentValidatorGetResponse": { + "type": "object", + "properties": { + "branch": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "description": "Branch UUID" + }, + "name": { + "type": "string", + "description": "Branch name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Branch info (present if branch_id was specified)" + }, + "content": { + "type": "array", + "items": {}, + "description": "Documents with their validation results" + }, + "model_id": { + "type": "string", + "description": "Model UUID" + } + }, + "required": [ + "branch", + "content", + "model_id" + ] + }, + "ContentFilterMode": { + "type": "string", + "enum": [ + "ALL", + "WITH_ISSUES", + "NO_ISSUES" + ], + "description": "Filter documents by issue status. ALL (default) returns all documents with at least one query. WITH_ISSUES returns only documents with at least one query issue, dashboard filter issue, or document error. NO_ISSUES returns only documents with zero issues and no document errors." + }, + "ModelsContentValidatorReplaceResponse": { + "type": "object", + "properties": { + "replaced_dashboard_filters_count": { + "type": "integer", + "description": "Number of dashboard filters replaced" + }, + "replaced_documents_count": { + "type": "integer", + "description": "Number of documents modified" + }, + "replaced_input_column_keys_count": { + "type": "integer", + "description": "Number of input columns whose key references were replaced" + }, + "replaced_queries_count": { + "type": "integer", + "description": "Number of queries replaced" + }, + "replaced_workbook_models_count": { + "type": "integer", + "description": "Number of workbook models replaced" + }, + "skipped_pr_required_count": { + "type": "integer", + "description": "Number of documents skipped due to pull request requirements" + } + }, + "required": [ + "replaced_dashboard_filters_count", + "replaced_documents_count", + "replaced_input_column_keys_count", + "replaced_queries_count", + "replaced_workbook_models_count", + "skipped_pr_required_count" + ] + }, + "ModelsContentValidatorReplaceBody": { + "type": "object", + "properties": { + "branch_id": { + "type": "string", + "description": "Optional branch ID" + }, + "creator_id": { + "type": "string", + "format": "uuid", + "description": "Restrict replacement to documents created by this user (user ID). Unknown IDs return 400." + }, + "find": { + "type": "string", + "minLength": 1, + "description": "The string to find" + }, + "find_or_replace_type": { + "type": "string", + "enum": [ + "FIELD", + "TOPIC", + "VIEW" + ], + "description": "Type of find/replace operation." + }, + "folder_paths": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Restrict replacement to documents in matching folder paths (prefix match). Documents with no folder are excluded unless \"\" is specified." + }, + "include_personal_folders": { + "type": "boolean", + "default": false, + "description": "Whether to include personal folders" + }, + "labels": { + "type": "string", + "description": "Comma-separated label names to scope replacement. Unknown labels return 400." + }, + "only_in_workbook_id": { + "type": "string", + "description": "Optional workbook ID to limit the replace scope" + }, + "replacement": { + "type": "string", + "minLength": 1, + "description": "The replacement string" + } + }, + "required": [ + "find", + "find_or_replace_type", + "replacement" + ] + }, + "ModelYamlResponse": { + "type": "object", + "properties": { + "checksums": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Checksums for each file" + }, + "files": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "YAML content for each file" + }, + "version": { + "type": "number", + "description": "Model version number" + }, + "viewNames": { + "type": "object", + "additionalProperties": {}, + "description": "View name mappings" + } + }, + "required": [ + "files", + "version" + ] + }, + "ModelYamlCreateRequestBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Branch ID for branch-aware operations" + }, + "fileName": { + "type": "string", + "minLength": 1, + "description": "File name to create or update" + }, + "mode": { + "type": "string", + "enum": [ + "combined", + "extension", + "staged", + "merged", + "fully-resolved" + ], + "default": "combined", + "description": "IDE mode for YAML operations" + }, + "commitMessage": { + "type": "string", + "description": "Commit message for git sync" + }, + "fetchedAtMillis": { + "type": "number", + "description": "Timestamp when the file was fetched" + }, + "fullyResolved": { + "type": "boolean", + "default": false, + "description": "Treat the posted YAML as fully resolved (with the extends chain expanded). Only valid with mode=combined." + }, + "previousChecksum": { + "type": "string", + "description": "Previous checksum for conflict detection" + }, + "yaml": { + "type": "string", + "description": "YAML content for the file" + } + }, + "required": [ + "fileName", + "yaml" + ], + "additionalProperties": false + }, + "AiAgentActionsResponse": { + "type": "object", + "properties": { + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiAgentAction" + }, + "description": "AI agent actions in display order: sample queries first, then skills. Topic-level entries follow model-level ones, and skills are deduped by id with topic skills winning over model skills." + } + }, + "required": [ + "records" + ] + }, + "AiAgentAction": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "sample", + "skill" + ], + "description": "Source of the entry: `sample` for `sample_queries` (model- or topic-level) and `skill` for `skills` (model- or topic-level).", + "example": "skill" + }, + "label": { + "type": "string", + "description": "Short, human-readable name for the action \u2014 chip text in client UIs and the visible \"prompt\" on the answer card.", + "example": "Revenue trends" + }, + "prompt": { + "type": "string", + "description": "Submit this string verbatim as the `prompt` on `POST /api/v1/ai/jobs`. For sample queries this is the raw prompt; for skills it is a pre-formatted wrapper around the skill's input.", + "example": "Skill:\nShow me the recent revenue trends grouped by month\u2026" + } + }, + "required": [ + "kind", + "label", + "prompt" + ] + }, + "QueryRunResponse": { + "type": "object", + "properties": { + "completedQueries": { + "type": "array", + "items": {}, + "description": "Queries that completed synchronously with their results." + }, + "jobIds": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Job IDs for queries running asynchronously. Use /api/v1/query/wait to poll for results.", + "example": [ + "job_abc123", + "job_def456" + ] + }, + "plan": { + "description": "Query execution plan (only present if planOnly is true)." + } + } + }, + "QueryTimeoutResponse": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Error message indicating the query timed out.", + "example": "Query timed out" + }, + "remaining_job_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Job IDs for queries that have not yet completed. Use /api/v1/query/wait to poll for results." + }, + "timed_out": { + "type": "boolean", + "enum": [ + true + ], + "description": "Always true for timeout responses.", + "example": true + } + }, + "required": [ + "detail", + "timed_out" + ] + }, + "QueryRunBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Optional model branch to run the query against. Must belong to the same shared model as the query. When omitted, the query runs against the shared model. Takes precedence over the legacy `?branch_id=` URL query parameter.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "cache": { + "type": "string", + "enum": [ + "disabled", + "normal", + "refresh", + "refresh_all" + ], + "description": "Cache policy for query execution. Controls whether to use cached results.", + "example": "normal" + }, + "environmentConnectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID of the environment to run the query against, overriding the connection environment inherited from the (target) user's session or default. Must be a configured environment of the query model's connection that the user can access.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "formatResults": { + "type": "boolean", + "description": "Whether to format result values (e.g., apply number formatting). Only valid when resultType is specified." + }, + "planOnly": { + "type": "boolean", + "default": false, + "description": "If true, returns only the query execution plan without running the query." + }, + "query": { + "description": "The semantic query definition including fields, filters, sorts, and other query parameters." + }, + "resultType": { + "type": "string", + "enum": [ + "csv", + "json", + "xlsx" + ], + "description": "Output format for the results. If not specified, returns base64-encoded Arrow format." + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "Alternate location for the `?userId=` query parameter. Prefer the query parameter \u2014 this body field exists for backwards compatibility. Supplying both forms results in a 400. Only valid for org-scoped API keys; when set, the user's attributes are applied for row-level security and connection-environment switching.", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + } + }, + "QueryWaitResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": {}, + "description": "Array of completed query results. Each result contains the query data or an error." + } + }, + "required": [ + "results" + ] + }, + "SchedulesListItem": { + "type": "object", + "properties": { + "alert": { + "type": "object", + "properties": { + "conditionQueryName": { + "type": [ + "string", + "null" + ], + "description": "Name of the query used for alert condition" + }, + "conditionType": { + "type": "string", + "description": "Type of alert condition: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" + } + }, + "required": [ + "conditionQueryName", + "conditionType" + ], + "description": "Alert configuration (only present for alert-type schedules)" + }, + "content": { + "type": "string", + "description": "Content type: dashboard or tile", + "example": "dashboard" + }, + "dashboardName": { + "type": "string", + "description": "Name of the dashboard", + "example": "Weekly Sales Report" + }, + "destinationType": { + "type": "string", + "description": "Delivery destination type: email, slack, webhook, sftp, s3, google_sheets", + "example": "email" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when the schedule was paused (null if active)" + }, + "format": { + "type": "string", + "description": "Output format: pdf, png, csv, xlsx, json, link_only", + "example": "pdf" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the schedule" + }, + "identifier": { + "type": "string", + "description": "Dashboard identifier", + "example": "12db1a0a" + }, + "lastCompletedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp of last completed delivery" + }, + "lastStatus": { + "type": [ + "string", + "null" + ], + "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" + }, + "name": { + "type": "string", + "description": "Name of the schedule", + "example": "Weekly Sales Report" + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the schedule owner" + }, + "ownerName": { + "type": "string", + "description": "Display name of the schedule owner", + "example": "John Doe" + }, + "recipientCount": { + "type": "number", + "description": "Number of recipients (-1 for non-email destinations)", + "example": 5 + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", + "example": "0 9 ? * MON *" + }, + "slackRecipientType": { + "type": [ + "string", + "null" + ], + "description": "Slack recipient type: Channel or Users (null for non-Slack)" + }, + "systemDisabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when system disabled the schedule (null if not system-disabled)" + }, + "systemDisabledReason": { + "type": [ + "string", + "null" + ], + "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for the schedule", + "example": "America/New_York" + } + }, + "required": [ + "content", + "dashboardName", + "destinationType", + "disabledAt", + "format", + "id", + "identifier", + "lastCompletedAt", + "lastStatus", + "name", + "ownerId", + "ownerName", + "recipientCount", + "schedule", + "slackRecipientType", + "systemDisabledAt", + "systemDisabledReason", + "timezone" + ] + }, + "SchedulesGetResponse": { + "type": "object", + "properties": { + "conditionQueryMapKey": { + "type": [ + "string", + "null" + ], + "description": "Query key used for alert condition (null for standard schedules)" + }, + "conditionType": { + "type": [ + "string", + "null" + ], + "description": "Alert condition type: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "Creation timestamp" + }, + "destinations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SchedulesGetDestination" + }, + "description": "Delivery destination configurations" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when the schedule was paused (null if active)" + }, + "entityId": { + "type": "string", + "description": "ID of the associated dashboard" + }, + "fanOut": { + "type": "boolean", + "description": "Whether personalized fan-out delivery is enabled", + "example": false + }, + "filterConfig": { + "description": "The effective dashboard filter configuration that the schedule will run with: the dashboard's current default filters merged under the schedule's persisted overrides, with any keys no longer present on the dashboard dropped. This matches what is shown when the schedule is opened in the Edit Delivery panel, and may differ from the schedule's persisted filter configuration." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Schedule UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "killJobsOnFailure": { + "type": "boolean", + "description": "Whether to stop the job if any queries fail", + "example": false + }, + "metadata": { + "description": "Schedule metadata including format options and delivery settings. Includes `timezoneOverride` (IANA timezone applied to query execution at render time, or null when no override is set)." + }, + "name": { + "type": "string", + "description": "Schedule name", + "example": "Weekly Sales Report" + }, + "organizationId": { + "type": "string", + "format": "uuid", + "description": "Organization UUID" + }, + "owner": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Schedule owner name" + } + }, + "required": [ + "name" + ] + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the schedule owner" + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", + "example": "0 9 ? * MON *" + }, + "systemDisabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when the system disabled the schedule" + }, + "systemDisabledReason": { + "type": [ + "string", + "null" + ], + "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for the schedule", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp" + } + }, + "required": [ + "conditionQueryMapKey", + "conditionType", + "createdAt", + "destinations", + "disabledAt", + "entityId", + "fanOut", + "id", + "killJobsOnFailure", + "name", + "organizationId", + "owner", + "ownerId", + "schedule", + "systemDisabledAt", + "systemDisabledReason", + "timezone", + "updatedAt" + ] + }, + "SchedulesGetDestination": { + "type": "object", + "properties": { + "format": { + "type": "string", + "description": "Output format: pdf, png, csv, xlsx, json, link_only", + "example": "pdf" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Destination UUID" + }, + "lastCompletedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp of last completed delivery" + }, + "lastStatus": { + "type": [ + "string", + "null" + ], + "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" + }, + "metadata": { + "description": "Destination-specific configuration (type, recipients, credentials, etc.)" + }, + "recipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SchedulesGetRecipient" + }, + "description": "Individual email recipients" + }, + "userGroupRecipients": { + "type": "array", + "items": {}, + "description": "User group recipients" + } + }, + "required": [ + "format", + "id", + "lastCompletedAt", + "lastStatus", + "recipients", + "userGroupRecipients" + ] + }, + "SchedulesGetRecipient": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Recipient ID" + }, + "membership": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Recipient email" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Recipient name" + } + }, + "required": [ + "email", + "name" + ] + } + }, + "required": [ + "user" + ] + }, + "membershipId": { + "type": "string", + "format": "uuid", + "description": "Membership ID" + } + }, + "required": [ + "id", + "membership", + "membershipId" + ] + }, + "SchedulesRecipientsGetResponse": { + "type": "object", + "properties": { + "recipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmailRecipient" + }, + "description": "List of individual recipients (for email destinations)." + }, + "type": { + "type": "string", + "enum": [ + "email", + "google_sheets", + "s3", + "sftp", + "slack", + "webhook" + ], + "description": "The schedule's destination type.", + "example": "email" + }, + "userGroupRecipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserGroupRecipient" + }, + "description": "List of user group recipients (for email destinations)." + } + }, + "required": [ + "type" + ] + }, + "EmailRecipient": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Recipient's email address.", + "example": "user@example.com" + }, + "id": { + "type": "string", + "description": "Unique identifier for the recipient." + }, + "name": { + "type": "string", + "description": "Recipient's display name.", + "example": "John Doe" + } + }, + "required": [ + "email", + "id", + "name" + ] + }, + "UserGroupRecipient": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "User group ID." + }, + "name": { + "type": "string", + "description": "User group name.", + "example": "Sales Team" + }, + "recipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmailRecipient" + }, + "description": "List of recipients in the user group." + } + }, + "required": [ + "id", + "name", + "recipients" + ] + }, + "SchedulesAddRecipientsResponse": { + "type": "object", + "properties": { + "addedGroupRecipientsCount": { + "type": "number", + "description": "Number of user group recipients added.", + "example": 1 + }, + "addedRecipientsCount": { + "type": "number", + "description": "Number of individual recipients added.", + "example": 2 + }, + "success": { + "type": "boolean", + "description": "Whether the operation was successful.", + "example": true + } + }, + "required": [ + "addedGroupRecipientsCount", + "addedRecipientsCount", + "success" + ] + }, + "SchedulesAddRecipientsBody": { + "type": "object", + "properties": { + "emails": { + "type": "array", + "items": { + "type": "string", + "format": "email" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of email addresses to add as recipients.", + "example": [ + "user@example.com" + ] + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to add as recipients.", + "example": [ + "123e4567-e89b-12d3-a456-426614174000" + ] + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of user UUIDs to add as recipients. Use the List users and List embed users endpoints to retrieve user IDs.", + "example": [ + "987fcdeb-51a2-43d7-9b56-254415f67890" + ] + } + } + }, + "SchedulesRemoveRecipientsResponse": { + "type": "object", + "properties": { + "removedGroupRecipientsCount": { + "type": "number", + "description": "Number of user group recipients removed.", + "example": 1 + }, + "removedRecipientsCount": { + "type": "number", + "description": "Number of individual recipients removed.", + "example": 2 + }, + "success": { + "type": "boolean", + "description": "Whether the operation was successful.", + "example": true + } + }, + "required": [ + "removedGroupRecipientsCount", + "removedRecipientsCount", + "success" + ] + }, + "SchedulesRemoveRecipientsBody": { + "type": "object", + "properties": { + "emails": { + "type": "array", + "items": { + "type": "string", + "format": "email" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of recipient email addresses to remove from the scheduled task.", + "example": [ + "user@example.com" + ] + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to remove as recipients.", + "example": [ + "123e4567-e89b-12d3-a456-426614174000" + ] + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of recipient user UUIDs to remove from the scheduled task. Use the List users and List embed users endpoints to retrieve user IDs.", + "example": [ + "987fcdeb-51a2-43d7-9b56-254415f67890" + ] + } + } + }, + "SchedulesTransferOwnershipBody": { + "type": "object", + "properties": { + "userId": { + "type": "string", + "format": "uuid", + "description": "The UUID of the user to transfer schedule ownership to. Use the List users endpoint to retrieve user IDs. The new owner must be a member of the same organization, not be the current owner, and have permission to view the dashboard associated with the schedule.", + "example": "987fcdeb-51a2-43d7-9b56-254415f67890" + } + }, + "required": [ + "userId" + ] + }, + "ScimUsersListResponse": { + "type": "object", + "properties": { + "Resources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScimUserResponse" + }, + "description": "List of SCIM users" + }, + "itemsPerPage": { + "type": "number", + "description": "Items per page" + }, + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "SCIM schema URIs" + }, + "startIndex": { + "type": "number", + "description": "Start index (1-based)" + }, + "totalResults": { + "type": "number", + "description": "Total number of results" + } + }, + "required": [ + "Resources", + "itemsPerPage", + "schemas", + "startIndex", + "totalResults" + ] + }, + "ScimUserResponse": { + "type": "object", + "properties": { + "active": { + "type": "boolean", + "description": "Whether the user is active" + }, + "displayName": { + "type": "string", + "description": "Display name" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID" + }, + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "SCIM schema URIs" + }, + "userName": { + "type": "string", + "format": "email", + "description": "Username (email)" + } + }, + "required": [ + "active", + "displayName", + "id", + "schemas", + "userName" + ] + }, + "ScimUserCreateRequest": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "Display name of the user", + "example": "John Doe" + }, + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + }, + "description": "Omni user attributes" + }, + "userName": { + "type": "string", + "format": "email", + "description": "Email address (username) of the user", + "example": "user@example.com" + } + }, + "required": [ + "displayName", + "userName" + ] + }, + "ScimUserPutRequest": { + "type": "object", + "properties": { + "active": { + "type": "boolean", + "default": true, + "description": "Whether the user is active" + }, + "displayName": { + "type": "string", + "description": "Display name of the user" + }, + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + }, + "description": "Enterprise SCIM user attributes" + }, + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + }, + "description": "Omni user attributes" + }, + "userName": { + "type": "string", + "format": "email", + "description": "Email address (username) of the user", + "example": "user@example.com" + } + }, + "required": [ + "userName" + ] + }, + "ScimUserPatchRequest": { + "type": "object", + "properties": { + "Operations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "replace", + "Replace", + "add", + "Add", + "Remove", + "remove" + ] + }, + "path": { + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + } + }, + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + } + }, + "active": { + "type": "boolean" + }, + "displayName": { + "type": "string" + }, + "userName": { + "type": "string", + "format": "email" + } + } + } + ] + } + }, + "required": [ + "op", + "value" + ] + }, + "minItems": 1, + "description": "List of patch operations to apply" + }, + "schemas": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "urn:ietf:params:scim:api:messages:2.0:PatchOp" + ] + }, + "description": "SCIM schema URIs" + } + }, + "required": [ + "Operations", + "schemas" + ] + }, + "ScimGroupsListResponse": { + "type": "object", + "properties": { + "Resources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScimGroupResponse" + }, + "description": "List of SCIM groups" + }, + "itemsPerPage": { + "type": "number", + "description": "Items per page" + }, + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "SCIM schema URIs" + }, + "startIndex": { + "type": "number", + "description": "Start index (1-based)" + }, + "totalResults": { + "type": "number", + "description": "Total number of results" + } + }, + "required": [ + "Resources", + "itemsPerPage", + "schemas", + "startIndex", + "totalResults" + ] + }, + "ScimGroupResponse": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "Group display name" + }, + "id": { + "type": "string", + "description": "SCIM group ID (miniUuid)" + }, + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Member display name" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "Member user ID" + } + }, + "required": [ + "display", + "value" + ] + }, + "description": "Group members" + }, + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "SCIM schema URIs" + } + }, + "required": [ + "displayName", + "id", + "schemas" + ] + }, + "ScimGroupsCreateBody": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "Display name of the group", + "example": "Engineering Team" + }, + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "value": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "value" + ] + }, + "default": [], + "description": "List of group members" + } + }, + "required": [ + "displayName" + ] + }, + "ScimGroupsReplaceBody": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "Display name of the group", + "example": "Engineering Team" + }, + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Display name of the member", + "example": "john.doe@example.com" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "display", + "value" + ] + }, + "description": "List of group members" + } + }, + "required": [ + "displayName", + "members" + ] + }, + "ScimGroupsPatchBody": { + "type": "object", + "properties": { + "Operations": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "replace", + "Replace" + ], + "description": "Operation type", + "example": "replace" + }, + "value": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "New display name", + "example": "Engineering Team" + }, + "id": { + "type": "string", + "description": "Group ID" + } + }, + "required": [ + "displayName" + ] + } + }, + "required": [ + "op", + "value" + ] + }, + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "remove", + "Remove" + ], + "description": "Operation type", + "example": "remove" + }, + "path": { + "type": "string", + "pattern": "members\\[value eq \"(.{36})\"\\]", + "description": "SCIM path for member to remove", + "example": "members[value eq \"550e8400-e29b-41d4-a716-446655440000\"]" + } + }, + "required": [ + "op", + "path" + ] + }, + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "add", + "Add" + ], + "description": "Operation type", + "example": "add" + }, + "path": { + "type": "string", + "enum": [ + "members" + ], + "description": "Path for members", + "example": "members" + }, + "value": { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Display name of the member", + "example": "john.doe@example.com" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "value" + ] + } + } + }, + "required": [ + "op", + "path", + "value" + ] + }, + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "replace", + "Replace" + ], + "description": "Operation type", + "example": "replace" + }, + "path": { + "type": "string", + "enum": [ + "members", + "displayName" + ], + "description": "Path for attribute to replace", + "example": "members" + }, + "value": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Display name of the member", + "example": "john.doe@example.com" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "value" + ] + } + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "op", + "path", + "value" + ] + } + ] + }, + "description": "List of SCIM patch operations" + }, + "schemas": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "urn:ietf:params:scim:api:messages:2.0:PatchOp" + ] + }, + "description": "SCIM schema URIs" + } + }, + "required": [ + "Operations", + "schemas" + ] + }, + "DocumentExportResponse": { + "type": "object", + "properties": { + "dashboard": { + "description": "Dashboard configuration and layout" + }, + "document": { + "type": "object", + "properties": { + "ephemeral": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "exportVersion": { + "type": "string" + }, + "fileUploads": { + "type": "object", + "additionalProperties": {} + }, + "queryModels": { + "type": "object", + "additionalProperties": {} + }, + "workbookModel": {} + }, + "required": [ + "document", + "exportVersion", + "queryModels" + ] + }, + "DocumentImportResponse": { + "type": "object", + "properties": { + "documentId": { + "type": "string", + "format": "uuid", + "description": "ID of the imported document" + }, + "identifier": { + "type": "string", + "description": "Document identifier (miniUuid)" + } + }, + "required": [ + "documentId", + "identifier" + ] + }, + "DocumentImportBody": { + "type": "object", + "properties": { + "baseModelId": { + "type": "string", + "format": "uuid", + "description": "Base model ID for the imported document" + }, + "dashboard": { + "description": "Dashboard export data" + }, + "document": { + "type": "object", + "properties": { + "ephemeral": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "exportVersion": { + "type": "string", + "enum": [ + "0.1" + ] + }, + "fileUploads": { + "type": "object", + "additionalProperties": {} + }, + "folderPath": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "queryModels": { + "type": "object", + "additionalProperties": {} + }, + "workbookModel": {} + }, + "required": [ + "baseModelId", + "document", + "exportVersion", + "queryModels" + ] + }, + "UserAttributesListResponse": { + "type": "object", + "properties": { + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "default_value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + { + "type": "null" + } + ], + "description": "Default value applied when no user-specific value is set. When multiple_values is true, this is an array. Null if no default is configured.", + "example": "us-east" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Human-readable description of the attribute and its purpose", + "example": "User region for row-level security filtering" + }, + "id": { + "type": "string", + "description": "Unique identifier for custom attributes. Empty string for system-defined attributes.", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "label": { + "type": "string", + "description": "Display name shown in the Omni UI", + "example": "Region" + }, + "multiple_values": { + "type": "boolean", + "description": "Whether the attribute accepts an array of values. When true, default_value and user-specific values are arrays.", + "example": false + }, + "name": { + "type": "string", + "description": "Reference name used in model SQL and in embed SSO URL parameters", + "example": "region" + }, + "system": { + "type": "boolean", + "description": "System-defined attributes (e.g. omni_user_id, omni_user_email) are built-in and read-only. Custom attributes have system=false.", + "example": false + }, + "type": { + "type": "string", + "enum": [ + "String", + "Number" + ], + "description": "Data type that determines valid values. String attributes accept text, Number attributes accept numeric values stored as strings for precision.", + "example": "String" + } + }, + "required": [ + "default_value", + "description", + "id", + "label", + "multiple_values", + "name", + "system", + "type" + ] + }, + "description": "All user attribute definitions in the organization, including both system-defined and custom attributes" + } + }, + "required": [ + "records" + ] + }, + "UploadsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Upload" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "Upload": { + "type": "object", + "properties": { + "connection_id": { + "type": "string", + "format": "uuid", + "description": "Connection ID the upload is associated with" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "When the file was uploaded" + }, + "file_name": { + "type": "string", + "description": "Original file name", + "example": "users.csv" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the upload" + }, + "in_db_as_table_name": { + "type": [ + "string", + "null" + ], + "description": "Database table name if uploaded to database scratch schema" + }, + "model_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Model ID the upload is associated with (inferred from connection's shared model if not explicitly set)" + }, + "size_bytes": { + "type": [ + "number", + "null" + ], + "description": "File size in bytes" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp" + }, + "uploaded_by_user": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "User ID of the uploader" + }, + "name": { + "type": "string", + "description": "Name of the user who uploaded the file" + } + }, + "required": [ + "id", + "name" + ], + "description": "User who uploaded the file" + }, + "view_name": { + "type": "string", + "description": "View name associated with the upload" + } + }, + "required": [ + "connection_id", + "created_at", + "file_name", + "id", + "in_db_as_table_name", + "model_id", + "size_bytes", + "updated_at", + "uploaded_by_user", + "view_name" + ] + }, + "UploadCreateResponse": { + "type": "object", + "properties": { + "fileName": { + "type": "string", + "description": "Original file name", + "example": "users.csv" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the upload" + }, + "inDbAsTableName": { + "type": "string", + "description": "Database table name in the scratch schema" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID the view was created in" + }, + "rowCount": { + "type": "integer", + "description": "Number of rows in the uploaded file" + }, + "truncated": { + "type": "boolean", + "description": "Whether the file was truncated due to row limit" + }, + "viewCreated": { + "type": "boolean", + "description": "Whether a view was created in the model" + }, + "viewName": { + "type": "string", + "description": "Name of the view created" + } + }, + "required": [ + "fileName", + "id", + "inDbAsTableName", + "modelId", + "rowCount", + "truncated", + "viewCreated", + "viewName" + ] + }, + "UploadCreateBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "UUID of the branch to create the view in (mutually exclusive with branchName)" + }, + "branchName": { + "type": "string", + "description": "Name of the branch to create the view in (mutually exclusive with branchId)" + }, + "file": { + "type": "string", + "description": "The CSV file to upload", + "format": "binary" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "UUID of the model to create the view in" + }, + "viewName": { + "type": "string", + "description": "Override the view name (defaults to sanitized file name)" + } + }, + "required": [ + "file", + "modelId" + ] + }, + "UploadDeleteResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the deletion was successful" + } + }, + "required": [ + "success" + ] + }, + "UsersGetModelRolesResponse": { + "type": "object", + "properties": { + "membershipId": { + "type": "string", + "format": "uuid", + "description": "The user membership ID" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoleAssignmentResult" + }, + "description": "List of role assignments" + } + }, + "required": [ + "membershipId", + "results" + ] + }, + "RoleAssignmentResult": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "The base role definition name", + "example": "VIEWER" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection this role applies to" + }, + "from": { + "$ref": "#/components/schemas/RoleOrigin" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model this role applies to" + }, + "priority": { + "type": "number", + "description": "Priority for role resolution (higher = more permissive)" + }, + "resolved": { + "type": "boolean", + "description": "Whether this is the resolved (effective) role" + }, + "roleName": { + "type": "string", + "description": "The role name (base or custom)", + "example": "VIEWER" + } + }, + "required": [ + "baseRole", + "connectionId", + "from", + "modelId", + "priority", + "resolved", + "roleName" + ] + }, + "RoleOrigin": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "USER" + ], + "description": "Role assigned directly to user" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "ORG" + ], + "description": "Role inherited from organization" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "BASE" + ], + "description": "Connection base role" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "depth": { + "type": "number", + "description": "Nesting depth of the group" + }, + "miniUuid": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "name": { + "type": "string", + "description": "Name of the group", + "example": "Engineering Team" + }, + "type": { + "type": "string", + "enum": [ + "GROUP" + ], + "description": "Role inherited from group membership" + } + }, + "required": [ + "depth", + "miniUuid", + "name", + "type" + ] + } + ], + "description": "Origin of this role assignment" + }, + "UsersAssignModelRoleResponse": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "The connection ID for this role assignment" + }, + "membershipId": { + "type": "string", + "format": "uuid", + "description": "The user membership ID" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The model ID for this role assignment" + }, + "roleName": { + "type": "string", + "description": "The assigned role name", + "example": "VIEWER" + } + }, + "required": [ + "connectionId", + "membershipId", + "modelId", + "roleName" + ] + }, + "UsersAssignModelRoleBody": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID for model-level role assignment. Required if connectionId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "roleName": { + "type": "string", + "minLength": 1, + "description": "Name of the role to assign (base or custom role)", + "example": "VIEWER" + } + }, + "required": [ + "roleName" + ] + }, + "UsersListEmailOnlyResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "User email address", + "example": "user@example.com" + }, + "user_attributes": { + "type": "object", + "additionalProperties": {}, + "description": "User attributes as key-value pairs" + }, + "user_id": { + "type": "string", + "format": "uuid", + "description": "User ID" + } + }, + "required": [ + "email", + "user_attributes", + "user_id" + ] + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "UsersCreateEmailOnlyResponse": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address of the created user", + "example": "user@example.com" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "ID of the created user" + } + }, + "required": [ + "email", + "userId" + ] + }, + "UsersCreateEmailOnlyBody": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address for the user", + "example": "user@example.com" + }, + "userAttributes": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "description": "Optional user attributes as key-value pairs" + } + }, + "required": [ + "email" + ] + }, + "UsersCreateEmailOnlyBulkResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address of the created user", + "example": "user@example.com" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "ID of the created user" + } + }, + "required": [ + "email", + "userId" + ] + }, + "description": "Results for each created user" + } + }, + "required": [ + "results" + ] + }, + "UsersCreateEmailOnlyBulkBody": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address for the user", + "example": "user@example.com" + }, + "userAttributes": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "description": "Optional user attributes as key-value pairs" + } + }, + "required": [ + "email" + ] + }, + "minItems": 1, + "maxItems": 20, + "description": "Array of users to create (1-20 users)" + } + }, + "required": [ + "users" + ] + }, + "UserGroupsGetModelRolesResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserGroupRoleAssignmentResult" + }, + "description": "List of role assignments" + }, + "userGroupId": { + "type": "string", + "description": "The user group short identifier", + "example": "abc123" + } + }, + "required": [ + "results", + "userGroupId" + ] + }, + "UserGroupRoleAssignmentResult": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "The base role definition name", + "example": "VIEWER" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection this role applies to" + }, + "from": { + "$ref": "#/components/schemas/UserGroupRoleOrigin" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model this role applies to" + }, + "priority": { + "type": "number", + "description": "Priority for role resolution (higher = more permissive)" + }, + "roleName": { + "type": "string", + "description": "The role name (base or custom)", + "example": "VIEWER" + } + }, + "required": [ + "baseRole", + "connectionId", + "from", + "modelId", + "priority", + "roleName" + ] + }, + "UserGroupRoleOrigin": { + "type": "object", + "properties": { + "depth": { + "type": "number", + "description": "Nesting depth of the group (0 for direct assignment)" + }, + "miniUuid": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "name": { + "type": "string", + "description": "Name of the group", + "example": "Engineering Team" + }, + "type": { + "type": "string", + "enum": [ + "GROUP" + ], + "description": "Role assigned to group" + } + }, + "required": [ + "depth", + "miniUuid", + "name", + "type" + ], + "description": "Origin of this role assignment" + }, + "UserGroupsAssignModelRoleResponse": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "The connection ID for this role assignment" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The model ID for this role assignment" + }, + "roleName": { + "type": "string", + "description": "The assigned role name", + "example": "VIEWER" + }, + "userGroupId": { + "type": "string", + "description": "The user group short identifier", + "example": "abc123" + } + }, + "required": [ + "connectionId", + "modelId", + "roleName", + "userGroupId" + ] + }, + "UserGroupsAssignModelRoleBody": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID for model-level role assignment. Required if connectionId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "roleName": { + "type": "string", + "minLength": 1, + "description": "Name of the role to assign (base or custom role)", + "example": "VIEWER" + } + }, + "required": [ + "roleName" + ] + }, + "WhoamiResponse": { + "type": "object", + "properties": { + "keyScope": { + "type": "string", + "enum": [ + "user", + "organization" + ], + "description": "Scope of the API key in use. A separate axis from role: a user-scoped key (PAT/OAuth) acts as a single user and cannot use SCIM, regardless of the user's org role." + }, + "orgRole": { + "type": "string", + "enum": [ + "MEMBER", + "ORG_ADMIN" + ], + "description": "The caller's organization role.", + "example": "MEMBER" + }, + "rolesByModel": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/WhoamiModelRole" + }, + "description": "Resolved role and effective permissions per model, keyed by model id. Connection role resolves per shared model, so this is per-model rather than a single global role." + }, + "rolesByModelTruncated": { + "type": "boolean", + "description": "Present and `true` when `rolesByModel` was truncated because the caller can access more models than the unfiltered limit. Pass a `modelId` filter to retrieve specific models." + }, + "user": { + "$ref": "#/components/schemas/WhoamiUser" + } + }, + "required": [ + "keyScope", + "orgRole", + "rolesByModel", + "user" + ] + }, + "WhoamiModelRole": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "The resolved base role (for custom roles, the base role they extend).", + "example": "QUERIER" + }, + "connectionId": { + "type": "string", + "description": "The connection this model belongs to" + }, + "permissions": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "QUERY_FULL_MODEL", + "QUERY_SQL", + "VIEW_SQL", + "QUERY_TOPICS", + "RUN_CONTENT_QUERIES", + "DOWNLOAD_CONTENT_QUERY", + "UPLOAD_CSV", + "SCHEDULE", + "SAVE_SPREADSHEETS", + "USE_AI", + "USE_IDE", + "USE_WORKBOOKS", + "UPDATE", + "UPDATE_RESTRICTED" + ] + }, + "description": "The caller's resolved/effective permissions on this model, reflecting custom roles. This is a capability signal for the directly-roleable model kinds (schema / shared / extension). It does not enumerate the permissions you derive on branch, workbook, and query models from your role on the base model they descend from \u2014 absence here does not mean you lack access on those derived models. MANAGE_MODEL, READ, and REFRESH_SCHEMA are also not reported: they derive from connection / sibling-model roles rather than a per-model rule.", + "example": [ + "QUERY_TOPICS", + "QUERY_SQL", + "USE_WORKBOOKS" + ] + }, + "roleName": { + "type": "string", + "description": "The resolved role name (informational; may be a custom role). Use `permissions` to decide capability.", + "example": "QUERIER" + } + }, + "required": [ + "baseRole", + "connectionId", + "permissions", + "roleName" + ] + }, + "WhoamiUser": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The caller's user id" + }, + "membershipId": { + "type": "string", + "description": "The caller's own membership id within this organization. This is the id accepted by the admin `GET /api/v1/users/{id}/model-roles` endpoint (it is distinct from the user id)." + } + }, + "required": [ + "id", + "membershipId" + ] + } + }, + "parameters": {} + }, + "paths": { + "/api/v1/ai/generate-query": { + "post": { + "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model.", + "operationId": "aiGenerateQuery", + "summary": "Generate query from natural language", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiGenerateQueryBody" + } + } + } + }, + "responses": { + "200": { + "description": "Query generated successfully. If runQuery is true (default), includes execution results. Check the error field \u2014 a 200 response may still contain a partial error if the query was generated but execution failed. When the organization is over its AI downgrade threshold the response also carries `downgradedModelTier` naming the cheaper tier the query was generated with.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiGenerateQueryResponse" + } + } + } + }, + "400": { + "description": "Invalid request. The prompt may be missing, the modelId may be invalid, or the AI was unable to generate a query for the given prompt.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "402": { + "description": "AI is unavailable because the organization is over its AI credit limit. The body carries the stable reason code `shutoff`.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditShutoffError" + } + } + } + }, + "403": { + "description": "Insufficient permissions. Requires the querier role on the target model and AI query generation must be enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model or topic was not found in the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/pick-topic": { + "post": { + "description": "Analyze a natural language prompt and determine which topic in the model is the best fit for answering the question. Useful as a preprocessing step before calling generate-query or submitting an AI job, especially when the user's question could relate to multiple topics.", + "operationId": "aiPickTopic", + "summary": "Pick the best topic for a prompt", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPickTopicBody" + } + } + } + }, + "responses": { + "200": { + "description": "Topic selected successfully. The returned topicId can be used as the topicName parameter in other AI endpoints.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPickTopicResponse" + } + } + } + }, + "400": { + "description": "Invalid request body. The prompt or modelId may be missing or malformed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. Requires the querier role on the target model and AI must be enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model was not found, or no accessible topics exist in the model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/search-omni-docs": { + "post": { + "description": "Search the Omni documentation using AI to answer questions about Omni features, configuration, modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer with source links to the relevant documentation pages.", + "operationId": "aiSearchOmniDocs", + "summary": "Search Omni documentation", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiSearchOmniDocsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Documentation search completed successfully. Returns a synthesized answer with source links.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiSearchOmniDocsResponse" + } + } + } + }, + "400": { + "description": "Invalid request. The question may be missing or exceed the 2000 character limit.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Omni Agent is not enabled for this organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/jobs": { + "post": { + "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15\u201360 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId.", + "operationId": "aiJobSubmit", + "summary": "Submit an AI job", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobSubmitBody" + } + } + } + }, + "responses": { + "201": { + "description": "Job created and queued for execution. Use the returned jobId to poll for status or retrieve results.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobSubmitResponse" + } + } + } + }, + "400": { + "description": "Invalid request body. Common causes: missing or empty prompt, invalid UUID for modelId/branchId/conversationId, invalid webhook URL format.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. The AI jobs API must be enabled for the organization, AI query generation must be enabled, and the user must have appropriate model access. User-scoped API keys cannot act on behalf of other users.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model was not found in the organization, the branchId does not belong to the specified model, or the topicName does not exist in the model (or is excluded by ai_chat_topics restrictions).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "409": { + "description": "An active job already exists for the specified conversationId. Wait for the current job to complete before submitting another job to the same conversation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}": { + "get": { + "description": "Get the current status of an AI job, including its state, progress information, and result summary. The response fields vary by state \u2014 for example, progress is only present during EXECUTING, and resultSummary is only present when COMPLETE. Poll this endpoint every 2\u20135 seconds until the job reaches a terminal state (COMPLETE, FAILED, or CANCELLED).", + "operationId": "aiJobStatus", + "summary": "Get AI job status", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Job status retrieved successfully. Check the state field to determine if the job is still running or has reached a terminal state.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobStatusResponse" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. AI query generation must be enabled for the organization and the caller must have permission to use AI on the job's model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Job not found. The job may not exist or may belong to a different organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/cancel": { + "post": { + "description": "Request cancellation of an AI job. This endpoint is idempotent \u2014 calling it on an already-cancelled or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING state cannot be cancelled as they are already finalizing results. Only the job owner or organization admins can cancel jobs.", + "operationId": "aiJobCancel", + "summary": "Cancel an AI job", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Cancellation request processed. The state field indicates the job's state after the attempt \u2014 CANCELLED if successful, or the current terminal state if the job had already completed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobCancelResponse" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Permission denied. Only the job owner or organization admins can cancel jobs.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Job not found. The job may not exist or may belong to a different organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "409": { + "description": "Concurrent modification conflict. The job state was changed by another request. Retry the cancellation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/result": { + "get": { + "description": "Retrieve the full result of a completed AI job, including all actions taken by the AI (queries generated, data retrieved) and the final summarized answer. Results are only available for jobs in COMPLETE state and are retained for 14 days after completion. The response is streamed directly from storage.", + "operationId": "aiJobResult", + "summary": "Get AI job result", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Full job result including the AI's actions, query results (with CSV data), and the final Markdown-formatted answer.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobResultResponse" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. AI query generation must be enabled for the organization and the caller must have permission to use AI on the job's model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Job not found, not in COMPLETE state, or result is no longer available (results are retained for 14 days).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/vis": { + "get": { + "description": "Render the visualization from a completed AI job as a PNG image. The endpoint extracts the visualization configuration from the job result, loads Arrow IPC data, and renders it server-side using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back through previous jobs in the conversation to find the original query data.", + "operationId": "aiJobVisualization", + "summary": "Render AI job visualization", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Visualization rendered as a PNG image. The Content-Type header is image/png.", + "content": { + "image/png": { + "schema": { + "format": "binary", + "type": "string" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. AI query generation must be enabled for the organization and the caller must have permission to use AI on the job's model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Job not found, not in COMPLETE state, or the apiAiVis feature flag is not enabled.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "422": { + "description": "The job completed but cannot be rendered as a visualization. Common causes: no visualization action in the job result, no Arrow IPC data available, missing summary fields, or the chart type is not renderable as an image (e.g., tables, KPIs).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError422" + } + } + } + } + } + } + }, + "/api/v1/ai/branding": { + "get": { + "description": "Returns the organization's AI helper branding \u2014 display name, optional custom logo URL, and copy used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's defaults when the organization hasn't configured custom branding, so the response is always populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity.", + "operationId": "aiBranding", + "summary": "Get AI helper branding", + "tags": [ + "AI" + ], + "responses": { + "200": { + "description": "AI branding retrieved successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiBrandingResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI access is required to view AI helper branding (no model in the org grants USE_AI to the caller).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + } + }, + "/api/v1/ai/conversations": { + "get": { + "description": "List the user's recent AI conversations, ordered by most-recent activity. Each record includes the conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to continue the thread), an optional name, and a one-line summary of the most recent prompt for display. Paginated via opaque `pageInfo.nextCursor` \u2014 pass it back as `cursor` to fetch the next page.", + "operationId": "aiConversationsList", + "summary": "List AI conversations", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of conversations.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiConversationsListResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + } + }, + "/api/v1/ai/conversations/{conversationId}": { + "get": { + "description": "Return a conversation with its full message history (alternating user / assistant turns). Used by clients (iOS app, embed widgets) to restore a prior conversation in their UI.", + "operationId": "aiConversationDetail", + "summary": "Get AI conversation with messages", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid" + }, + "required": true, + "name": "conversationId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Conversation with messages in chronological order.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiConversationDetailResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI access is required to view chat conversations (no model in the org grants USE_AI to the caller).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Conversation not found. User-scoped keys also get 404 (not 403) when the conversation exists but belongs to a different user \u2014 existence of another user's conversations is not disclosed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/credit-controls": { + "get": { + "description": "Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per-user credit limit, plus read-only context (the credit limit, usage so far this billing period, and the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same AI-admin permission.", + "operationId": "aiCreditControlsGet", + "summary": "Get AI credit controls", + "tags": [ + "AI" + ], + "responses": { + "200": { + "description": "Current credit controls. Thresholds are `null` when the corresponding control is off.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditControlsResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions, or AI credit controls are not enabled for the organization. Requires AI-admin access.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + }, + "patch": { + "description": "Update the organization's AI credit controls: the downgrade and shutoff thresholds and the default per-user credit limit (userDefaultCredits). All fields are optional and tri-state: omit a field to leave it unchanged, send `null` to turn that control off (for userDefaultCredits: unlimited by default), or send a non-negative number to set it. At least one field is required. The `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the full current state, the same shape as GET.", + "operationId": "aiCreditControlsUpdate", + "summary": "Update AI credit controls", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditControlsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Thresholds updated. Returns the full current state.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditControlsResponse" + } + } + } + }, + "400": { + "description": "Invalid request. Common causes: empty body, a negative value, an unknown field, or downgradeCredits above shutoffCredits.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions, or AI credit controls are not enabled. Requires AI-admin access.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + } + }, + "/api/v1/ai/credit-controls/users": { + "get": { + "description": "List the organization's active individual user AI credit limits, ordered by userId ascending. Only users with an individual limit appear \u2014 everyone else follows the org default. A `null` creditLimit is an explicit unlimited override, distinct from following the default. Paginated via opaque cursors: pass `pageInfo.nextCursor` from one response as the `cursor` query parameter on the next request. Requires the same manage-user-attributes permission as the PATCH.", + "operationId": "aiCreditControlsUsersList", + "summary": "List individual users' AI credit limits", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + } + ], + "responses": { + "200": { + "description": "One page of users' individual AI credit limits.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditControlsUsersListResponse" + } + } + } + }, + "400": { + "description": "Invalid cursor or pageSize.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions, or per-user AI credit limits are not enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + }, + "patch": { + "description": "Set individual users' AI credit limits in bulk. Each entry names a user (`userId`) and either sets an individual limit (`creditLimit`: a non-negative number, or `null` for unlimited) or removes one (`useDefaultLimit: true`) so the user follows the org default. Each userId may appear at most once and must be a member of the organization. All updates are applied in one transaction, so either every entry takes effect or none do \u2014 an invalid userId fails the whole request with a 404 naming it. Requires the same manage-user-attributes permission as the AI credit limit settings pages.", + "operationId": "aiCreditControlsUsersUpdate", + "summary": "Set individual users' AI credit limits", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiUserCreditLimitsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "All entries applied. Returns each user's effective limit, in request order.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiUserCreditLimitsResponse" + } + } + } + }, + "400": { + "description": "Invalid request. Common causes: an empty users array, more than 1000 entries, an entry with both creditLimit and useDefaultLimit (or neither), a negative creditLimit, or a duplicated userId.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions, per-user AI credit limits are not enabled, or credit controls editing is disabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "A userId is not a member of the organization; the response names the first invalid id. No limits are changed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/routines": { + "get": { + "description": "List routines for the calling user, newest first. Includes routines paused by the owner or disabled by Omni, but excludes deleted routines. Use `pageInfo.nextCursor` from one response as the `cursor` query parameter on the next request. Organization API keys can pass `?userId=` to list routines for a specific organization member.", + "operationId": "routinesList", + "summary": "List routines", + "tags": [ + "AI Routines" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Field to sort results by" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of routines.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutinesListResponse" + } + } + } + }, + "400": { + "description": "Invalid pagination cursor or `userId` value.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to list routines for another user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The `userId` membership was not found in the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + }, + "post": { + "description": "Create a routine that runs a saved prompt on a schedule and delivers the AI response through a single destination \u2014 email (one or more recipients / user groups) or Slack (a single channel or direct message). Each scheduled run executes once using the routine owner's permissions, and every recipient receives the same result. Organization API keys can pass `?userId=` to create the routine for a specific organization member.", + "operationId": "routineCreate", + "summary": "Create a routine", + "tags": [ + "AI Routines" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Routine created successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body, recipient configuration, schedule, or timezone. Also returned when the schedule is more frequent than the organization allows.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI routines or AI query generation are not enabled for the organization, or the API key cannot act on behalf of the requested user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Model, branch, or topic not found, or not accessible to the requested user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "429": { + "description": "The resolved user already has the maximum number of active routines.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError429" + } + } + } + } + } + } + }, + "/api/v1/ai/routines/{id}": { + "get": { + "description": "Get a single routine, including the status of its most recent completed run.", + "operationId": "routineGet", + "summary": "Get a routine", + "tags": [ + "AI Routines" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the routine." + }, + "required": true, + "description": "The UUID of the routine.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Routine details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineResponse" + } + } + } + }, + "400": { + "description": "Invalid routine ID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to access another user's routine.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Routine not found or has been deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + }, + "patch": { + "description": "Update a routine. All request fields are optional, and only supplied fields are changed. Supplying `destination` replaces the full recipient configuration.", + "operationId": "routineUpdate", + "summary": "Update a routine", + "tags": [ + "AI Routines" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the routine." + }, + "required": true, + "description": "The UUID of the routine.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Updated routine details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineResponse" + } + } + } + }, + "400": { + "description": "Invalid routine ID, request body, recipient configuration, schedule, or timezone.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to update another user's routine.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Routine not found or has been deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + }, + "delete": { + "description": "Delete a routine. It stops running immediately and no longer appears in list or get responses.", + "operationId": "routineDelete", + "summary": "Delete a routine", + "tags": [ + "AI Routines" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the routine." + }, + "required": true, + "description": "The UUID of the routine.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Routine deleted successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineDeleteResponse" + } + } + } + }, + "400": { + "description": "Invalid routine ID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to delete another user's routine.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Routine not found or has already been deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/routines/{id}/trigger": { + "post": { + "description": "Run a routine immediately, in addition to its schedule. The run executes once using the routine owner's permissions and delivers the AI response to every configured recipient \u2014 it is not a private preview. Returns once the run has started; the result is delivered asynchronously. Organization API keys can pass `?userId=` to act on behalf of a specific organization member.", + "operationId": "routineTrigger", + "summary": "Run a routine now", + "tags": [ + "AI Routines" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the routine." + }, + "required": true, + "description": "The UUID of the routine.", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "202": { + "description": "The run has started.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RoutineTriggerResponse" + } + } + } + }, + "400": { + "description": "Invalid routine ID, or the routine cannot run as configured (e.g. its model, branch, or owner is no longer accessible).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to run another user's routine.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The routine does not exist or cannot be triggered (deleted, paused, or disabled by Omni).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "409": { + "description": "A run is already in progress for this routine.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } + } + } + } + }, + "/api/v1/api-keys": { + "get": { + "description": "Returns all API tokens in the organization, including organization-level keys, personal access tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions.", + "operationId": "apiKeysList", + "summary": "List API tokens", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Cursor from the previous response (token UUID)" + }, + "required": false, + "description": "Cursor from the previous response (token UUID)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "createdAt", + "name" + ], + "default": "createdAt" + }, + "required": false, + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "organization", + "personal", + "mcp" + ], + "description": "Filter by API token type. When omitted, all types are returned.", + "example": "personal" + }, + "required": false, + "description": "Filter by API token type. When omitted, all types are returned.", + "name": "type", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of API tokens", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyListResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" + } + } + } + }, + "/api/v1/api-keys/{id}": { + "get": { + "description": "Returns a single API token by id. Requires organization admin permissions.", + "operationId": "apiKeysGet", + "summary": "Get API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The requested API token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKey" + } + } + } + }, + "400": { + "description": "Malformed `id` (must be a UUID)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Token not found in this organization" + } + } + }, + "put": { + "description": "Enables or disables an API token. Requires organization admin permissions.", + "operationId": "apiKeysUpdate", + "summary": "Enable or disable an API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "The updated API token", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKey" + } + } + } + }, + "400": { + "description": "Invalid body, malformed `id`, or missing/malformed `Authorization` header" + }, + "403": { + "description": "Invalid bearer token, or caller lacks organization admin permissions" + }, + "404": { + "description": "Token not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + }, + "delete": { + "description": "Revokes an API token by permanently deleting it. Works for all token types. Requires organization admin permissions.", + "operationId": "apiKeysDelete", + "summary": "Revoke an API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The token was revoked", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyDeleteResponse" + } + } + } + }, + "400": { + "description": "Malformed `id`, or missing/malformed `Authorization` header" + }, + "403": { + "description": "Invalid bearer token, or caller lacks organization admin permissions" + }, + "404": { + "description": "Token not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + } + }, + "/api/v1/connections": { + "get": { + "operationId": "connectionsList", + "summary": "List connections", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Filter by database name (case-insensitive contains)", + "example": "analytics" + }, + "required": false, + "description": "Filter by database name (case-insensitive contains)", + "name": "database", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by dialect(s). Comma-separated list for multiple values", + "example": "snowflake,bigquery" + }, + "required": false, + "description": "Filter by dialect(s). Comma-separated list for multiple values", + "name": "dialect", + "in": "query" + }, + { + "schema": { + "type": "boolean", + "description": "Include soft-deleted connections in results", + "example": false + }, + "required": false, + "description": "Include soft-deleted connections in results", + "name": "includeDeleted", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by connection name (case-insensitive contains)", + "example": "Production" + }, + "required": false, + "description": "Filter by connection name (case-insensitive contains)", + "name": "name", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction", + "example": "desc" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "database", + "dialect", + "name" + ], + "description": "Field to sort by", + "example": "name" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of connections", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "allowBranchConnectionEnvironments": { + "type": [ + "boolean", + "null" + ], + "description": "Whether a branch may select its own connection environment. When user-attribute environment selection is also enabled, a branch selection overrides the user attribute.", + "example": false + }, + "baseRole": { + "type": [ + "string", + "null" + ], + "description": "Default role for users on this connection", + "example": "QUERIER" + }, + "branchConnectionEnvironmentOverridesUserAttr": { + "type": [ + "boolean", + "null" + ], + "deprecated": true, + "description": "Deprecated alias for `allowBranchConnectionEnvironments`; same value. Use `allowBranchConnectionEnvironments` instead.", + "example": false + }, + "createdAt": { + "type": "string", + "description": "Timestamp when connection was created (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "database": { + "type": [ + "string", + "null" + ], + "description": "Database name", + "example": "analytics_db" + }, + "defaultSchema": { + "type": [ + "string", + "null" + ], + "description": "Default schema for the connection", + "example": "public" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when connection was deleted (ISO 8601)", + "example": null + }, + "dialect": { + "type": "string", + "enum": [ + "snowflake", + "bigquery", + "redshift", + "postgres", + "mysql", + "mariadb", + "databricks", + "databricks_lakebase", + "trino", + "athena", + "duckdb", + "motherduck", + "sqlserver", + "clickhouse", + "singlestore" + ], + "description": "Database dialect type", + "example": "snowflake" + }, + "environmentConnectionSwitchesSchemaModel": { + "type": [ + "boolean", + "null" + ], + "description": "Whether environment connections switch schema model", + "example": false + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection identifier", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "name": { + "type": "string", + "description": "Connection display name", + "example": "Production Snowflake" + }, + "updatedAt": { + "type": "string", + "description": "Timestamp when connection was last updated (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "userAttributeNameForConnectionEnvironments": { + "type": [ + "string", + "null" + ], + "description": "User attribute name used for connection environments", + "example": "region" + }, + "userAttributeValuesForDefaultEnvironment": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default user attribute values for the base environment", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "allowBranchConnectionEnvironments", + "baseRole", + "branchConnectionEnvironmentOverridesUserAttr", + "createdAt", + "database", + "defaultSchema", + "deletedAt", + "dialect", + "environmentConnectionSwitchesSchemaModel", + "id", + "name", + "updatedAt", + "userAttributeNameForConnectionEnvironments", + "userAttributeValuesForDefaultEnvironment" + ], + "description": "Connection object", + "title": "Connection" + }, + "description": "List of connections" + } + }, + "required": [ + "connections" + ], + "description": "List connections response", + "title": "ConnectionsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + }, + "post": { + "description": "Create a new database connection. The request body varies by dialect - see dialect-specific documentation for required fields.", + "operationId": "connectionsCreate", + "summary": "Create connection", + "tags": [ + "Connections" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "acceptsLicense": { + "type": "boolean", + "description": "Acceptance of the license terms. Required for Oracle connections.", + "example": true + }, + "allowsUserSpecificTimezones": { + "type": "boolean", + "default": false, + "description": "Whether to allow users to specify their own timezones", + "example": false + }, + "alwaysScopeViewNames": { + "type": "boolean", + "description": "Whether to always include schema (and catalog) prefixes in generated view names, even for tables in the default schema. Defaults to true for dialects that support multiple catalogs, false otherwise.", + "example": true + }, + "authenticationType": { + "type": "string", + "description": "Authentication type. Applicable for BigQuery, MSSQL, Snowflake, Databricks, and Athena.", + "example": "snowflake-password" + }, + "awsRoleArn": { + "type": "string", + "description": "AWS IAM role ARN. Applicable for Athena only.", + "example": "arn:aws:iam::123456789012:role/OmniAthenaRole" + }, + "baseRole": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "RESTRICTED_QUERIER", + "QUERIER", + "MODELER", + "CONNECTION_ADMIN" + ], + "description": "The default role for users accessing the connection", + "example": "QUERIER" + }, + "database": { + "type": "string", + "description": "The default database/catalog to connect to. For BigQuery, this is the project ID. For Athena, this is the data catalog.", + "example": "analytics_db" + }, + "defaultSchema": { + "type": "string", + "description": "The default schema to use. Required for MSSQL.", + "example": "public" + }, + "dialect": { + "type": "string", + "enum": [ + "athena", + "bigquery", + "clickhouse", + "databricks", + "databricks_lakebase", + "exasol", + "mariadb", + "motherduck", + "mssql", + "mysql", + "oracle", + "postgres", + "redshift", + "sap_hana", + "snowflake", + "starrocks", + "trino" + ], + "description": "The database dialect", + "example": "snowflake" + }, + "enableDbSemanticLayerIntegration": { + "type": "boolean", + "default": false, + "description": "Enable the dialect-native semantic layer integration. Applicable for Snowflake and Databricks.", + "example": false + }, + "enableDbSemanticLayerTopics": { + "type": "boolean", + "default": false, + "description": "Enable the dialect-native semantic layer topics. Applicable for Snowflake and Databricks.", + "example": false + }, + "externalOauthAudience": { + "type": "string", + "description": "External OAuth audience claim. Applicable for Snowflake." + }, + "externalOauthAuthorizationUrl": { + "type": "string", + "format": "uri", + "description": "External OAuth authorization URL (must be HTTPS). Applicable for Snowflake.", + "example": "https://oauth.example.com/authorize" + }, + "externalOauthTokenUrl": { + "type": "string", + "format": "uri", + "description": "External OAuth token URL (must be HTTPS). Applicable for Snowflake.", + "example": "https://oauth.example.com/token" + }, + "host": { + "type": "string", + "description": "The hostname or IP address of the database server. For Snowflake, provide only the account identifier.", + "example": "myaccount" + }, + "hostOverride": { + "type": "string", + "description": "Custom Snowflake host (when not using the account identifier). Mutually exclusive with `host`.", + "example": "myaccount.snowflakecomputing.com" + }, + "includeOtherCatalogs": { + "type": "string", + "description": "Comma-separated list of other catalogs/databases to include. Only applicable for databases that support multi-catalog queries.", + "example": "other_project1,other_project2" + }, + "includeSchemas": { + "type": "string", + "description": "Comma-separated list of schemas to include. Leave empty to include all schemas.", + "example": "public,analytics" + }, + "inferRelationshipsFromColumnNames": { + "type": "boolean", + "default": true, + "description": "Whether to infer relationships from column-name conventions during schema refresh. Defaults to true.", + "example": true + }, + "inferRelationshipsFromForeignKeys": { + "type": "boolean", + "default": false, + "description": "Whether to infer relationships from declared foreign keys during schema refresh. Currently honored for Postgres and Snowflake.", + "example": false + }, + "maxBillingBytes": { + "type": "string", + "description": "Maximum bytes that can be billed for a BigQuery query. Applicable for BigQuery only.", + "example": "1000000000" + }, + "name": { + "type": "string", + "description": "A descriptive name for the connection", + "example": "Production Warehouse" + }, + "oauthClientId": { + "type": "string", + "description": "OAuth client ID for admin schema refresh. Applicable for Snowflake and Databricks." + }, + "oauthClientSecretUnencrypted": { + "type": "string", + "description": "OAuth client secret for admin schema refresh. Applicable for Snowflake and Databricks." + }, + "offloadedSchemas": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Schemas whose tables should be queried via the offloaded engine. Accepts a comma-separated string or an array of schema names.", + "example": [ + "analytics_archive" + ] + }, + "passwordUnencrypted": { + "type": "string", + "description": "The password to authenticate with. For BigQuery, this must be the JSON service account key file content. For Snowflake with keypair authentication, this can be omitted." + }, + "port": { + "type": "integer", + "description": "The port number for the database connection. Not required for Snowflake, MotherDuck, BigQuery, Databricks, and Athena.", + "example": 5432 + }, + "privateKey": { + "type": "string", + "description": "An RSA key for keypair authentication. Omni will automatically add PEM headers if none are provided. Applicable for Snowflake only." + }, + "queryTimeoutSeconds": { + "type": "integer", + "maximum": 3600, + "description": "The timeout in seconds for queries. Maximum value is 3600 (1 hour). Only applicable for databases that support query timeouts.", + "example": 900 + }, + "queryTimezone": { + "type": "string", + "description": "The timezone to use for queries", + "example": "NONE" + }, + "region": { + "type": "string", + "description": "Required for BigQuery and Athena connections. For BigQuery, specify a region like \"us\". For Athena, specify an AWS region like \"us-east-1\".", + "example": "us-east-1" + }, + "scratchSchema": { + "type": "string", + "description": "Schema to use for data input (upload) tables. If not specified, a suitable default will be chosen.", + "example": "omni_scratch" + }, + "systemTimezone": { + "type": "string", + "description": "The timezone to use for the system", + "example": "UTC" + }, + "trustServerCertificate": { + "type": "boolean", + "default": false, + "description": "Whether to trust the server certificate. Applicable for MSSQL, Exasol, ClickHouse, Trino, and SAP HANA.", + "example": false + }, + "useMachineAuth": { + "type": "boolean", + "description": "Whether to authenticate using machine credentials (OAuth M2M). Applicable for Athena and Databricks.", + "example": false + }, + "username": { + "type": "string", + "description": "The username to authenticate with. For BigQuery, this is the client email from the service account.", + "example": "analytics_user" + }, + "warehouse": { + "type": "string", + "description": "Required for Snowflake (specify the warehouse) and Databricks (specify the HTTP path). May be omitted for Snowflake OAuth connections, in which case each user's Snowflake default warehouse applies.", + "example": "COMPUTE_WH" + }, + "wifAudience": { + "type": "string", + "description": "Full resource name of the workload identity pool provider. Required for BigQuery workload identity federation authentication.", + "example": "//iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider" + }, + "wifServiceAccountEmail": { + "type": "string", + "description": "Service account to impersonate for BigQuery workload identity federation authentication. When omitted, the federated identity is used directly.", + "example": "omni@my-project.iam.gserviceaccount.com" + } + }, + "required": [ + "dialect", + "name", + "passwordUnencrypted" + ], + "description": "Request body for creating a database connection. Required fields: dialect, name, passwordUnencrypted. Additional fields may be required depending on the dialect.", + "title": "ConnectionsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Connection created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "data": { + "type": "string", + "format": "uuid", + "description": "Created connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "data", + "success" + ], + "description": "Create connection response", + "title": "ConnectionsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or dialect" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + } + }, + "/api/v1/connections/{id}": { + "get": { + "description": "Fetch a single connection by ID.", + "operationId": "connectionsGet", + "summary": "Get connection", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Connection object", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connection": { + "type": "object", + "properties": { + "allowBranchConnectionEnvironments": { + "type": [ + "boolean", + "null" + ], + "description": "Whether a branch may select its own connection environment. When user-attribute environment selection is also enabled, a branch selection overrides the user attribute.", + "example": false + }, + "baseRole": { + "type": [ + "string", + "null" + ], + "description": "Default role for users on this connection", + "example": "QUERIER" + }, + "branchConnectionEnvironmentOverridesUserAttr": { + "type": [ + "boolean", + "null" + ], + "deprecated": true, + "description": "Deprecated alias for `allowBranchConnectionEnvironments`; same value. Use `allowBranchConnectionEnvironments` instead.", + "example": false + }, + "createdAt": { + "type": "string", + "description": "Timestamp when connection was created (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "database": { + "type": [ + "string", + "null" + ], + "description": "Database name", + "example": "analytics_db" + }, + "defaultSchema": { + "type": [ + "string", + "null" + ], + "description": "Default schema for the connection", + "example": "public" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when connection was deleted (ISO 8601)", + "example": null + }, + "dialect": { + "type": "string", + "enum": [ + "snowflake", + "bigquery", + "redshift", + "postgres", + "mysql", + "mariadb", + "databricks", + "databricks_lakebase", + "trino", + "athena", + "duckdb", + "motherduck", + "sqlserver", + "clickhouse", + "singlestore" + ], + "description": "Database dialect type", + "example": "snowflake" + }, + "environmentConnectionSwitchesSchemaModel": { + "type": [ + "boolean", + "null" + ], + "description": "Whether environment connections switch schema model", + "example": false + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection identifier", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "name": { + "type": "string", + "description": "Connection display name", + "example": "Production Snowflake" + }, + "updatedAt": { + "type": "string", + "description": "Timestamp when connection was last updated (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "userAttributeNameForConnectionEnvironments": { + "type": [ + "string", + "null" + ], + "description": "User attribute name used for connection environments", + "example": "region" + }, + "userAttributeValuesForDefaultEnvironment": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default user attribute values for the base environment", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "allowBranchConnectionEnvironments", + "baseRole", + "branchConnectionEnvironmentOverridesUserAttr", + "createdAt", + "database", + "defaultSchema", + "deletedAt", + "dialect", + "environmentConnectionSwitchesSchemaModel", + "id", + "name", + "updatedAt", + "userAttributeNameForConnectionEnvironments", + "userAttributeValuesForDefaultEnvironment" + ], + "description": "Connection object", + "title": "Connection" + } + }, + "required": [ + "connection" + ], + "description": "Get connection response", + "title": "ConnectionsGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied \u2014 caller lacks READ on the connection" + }, + "404": { + "description": "Connection does not exist" + } + } + }, + "patch": { + "description": "Update connection settings including base role, environment user attributes, and credentials.\n\nCredential fields:\n- `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery)\n- `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication\n\nNote: Credentials are encrypted at rest and never returned in API responses.", + "operationId": "connectionsUpdate", + "summary": "Update connection", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "Default role to assign to this connection", + "example": "QUERIER" + }, + "environmentUserAttribute": { + "type": [ + "object", + "null" + ], + "properties": { + "attributeName": { + "type": "string", + "description": "Name of the user attribute for environment selection", + "example": "region" + }, + "defaultValues": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default values for the user attribute", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "attributeName", + "defaultValues" + ], + "description": "User attribute settings for connection environments" + }, + "passwordUnencrypted": { + "type": "string", + "description": "New password or service account key. For BigQuery, this must be the JSON service account key file content." + }, + "privateKey": { + "type": "string", + "description": "RSA private key for keypair authentication (Snowflake only). Must be PEM-encoded PKCS#8 format, minimum 2048-bit." + } + }, + "description": "Request body for updating connection attributes and credentials. At least one field must be provided.", + "title": "ConnectionsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Connection updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Status message describing what was updated", + "example": "Updated connection default role." + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "Update connection response", + "title": "ConnectionsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - at least one field must be provided" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "delete": { + "description": "Archive a connection (move to trash). Archived connections can be restored from the trash in the connection settings UI.\n\nA connection that is already archived returns 410.", + "operationId": "connectionsDelete", + "summary": "Delete connection", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Connection moved to trash", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Status message describing the result", + "example": "Connection moved to trash." + }, + "success": { + "type": "boolean", + "description": "True when the connection was archived", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "Archive connection response", + "title": "ConnectionsDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + }, + "410": { + "description": "Connection has already been archived" + } + } + } + }, + "/api/v1/connections/{connectionId}/dbt": { + "get": { + "operationId": "connectionsDbtGet", + "summary": "Get dbt configuration", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "dbt configuration for the connection", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "type": "object", + "properties": { + "autogenRelationships": { + "type": "boolean", + "description": "Whether relationships are auto-generated from dbt", + "example": true + }, + "branch": { + "type": "string", + "description": "Git branch name", + "example": "main" + }, + "dbtVersion": { + "type": "string", + "description": "dbt version being used", + "example": "Auto" + }, + "enableSemanticLayer": { + "type": "boolean", + "description": "Whether the dbt semantic layer integration is enabled", + "example": false + }, + "enableVirtualSchemas": { + "type": "boolean", + "description": "Whether virtual schemas are enabled", + "example": false + }, + "projectRootPath": { + "type": [ + "string", + "null" + ], + "description": "Path to dbt project root", + "example": "dbt_project" + }, + "sshUrl": { + "type": "string", + "description": "SSH URL for git repository", + "example": "git@github.com:org/repo.git" + }, + "supportsDbt": { + "type": "boolean", + "enum": [ + true + ], + "description": "Indicates dbt is supported and configured", + "example": true + } + }, + "required": [ + "autogenRelationships", + "branch", + "dbtVersion", + "enableSemanticLayer", + "enableVirtualSchemas", + "projectRootPath", + "sshUrl", + "supportsDbt" + ], + "description": "dbt repository configuration response", + "title": "DbtConfiguredResponse" + }, + { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Message explaining dbt status", + "example": "dbt not configured for this connection" + }, + "supportsDbt": { + "type": "boolean", + "description": "Whether the connection dialect supports dbt", + "example": true + } + }, + "required": [ + "message", + "supportsDbt" + ], + "description": "Response when dbt is not configured", + "title": "DbtNotConfiguredResponse" + } + ], + "description": "dbt configuration response", + "title": "ConnectionsDbtGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "put": { + "operationId": "connectionsDbtUpdate", + "summary": "Update dbt configuration", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "autogenRelationships": { + "type": "boolean", + "description": "Automatically generate relationships from dbt", + "example": true + }, + "branch": { + "type": "string", + "minLength": 1, + "description": "Git branch name", + "example": "main" + }, + "dbtVersion": { + "type": [ + "string", + "null" + ], + "description": "dbt version to use. Supported: Auto, 1.11, 1.12", + "example": "1.11" + }, + "enableSemanticLayer": { + "type": "boolean", + "default": false, + "description": "Enable dbt semantic layer integration", + "example": false + }, + "enableVirtualSchemas": { + "type": "boolean", + "description": "Enable virtual schemas from dbt", + "example": false + }, + "projectRootPath": { + "anyOf": [ + { + "type": "string", + "pattern": "^(?!\\/)(?!.*\\.\\.)[\\w ./-]+$" + }, + { + "type": "string", + "enum": [ + "" + ] + }, + { + "type": [ + "object", + "null" + ], + "enum": [ + null + ] + }, + { + "type": "null" + } + ], + "default": null, + "description": "Path to dbt project root within repository", + "example": "dbt_project" + }, + "rotateKeys": { + "type": "boolean", + "default": false, + "description": "Rotate SSH deploy keys", + "example": false + }, + "sshUrl": { + "type": "string", + "minLength": 1, + "description": "SSH URL for git repository", + "example": "git@github.com:org/repo.git" + } + }, + "required": [ + "autogenRelationships", + "branch", + "enableVirtualSchemas", + "sshUrl" + ], + "description": "dbt repository configuration", + "title": "ConnectionsDbtUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "dbt configuration updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "dbt configuration updated successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "dbt update response", + "title": "ConnectionsDbtUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or validation error" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "delete": { + "operationId": "connectionsDbtDelete", + "summary": "Delete dbt configuration", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "dbt configuration deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "dbt repository unlinked successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "dbt delete response", + "title": "ConnectionsDbtDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found or dbt not configured" + } + } + } + }, + "/api/v1/connections/{connectionId}/dbt/environments": { + "get": { + "description": "List all dbt environments for a connection.", + "operationId": "connectionsDbtEnvironmentsList", + "summary": "List dbt environments", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name" + ], + "default": "name", + "description": "Field to sort results by", + "example": "name" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of dbt environments", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection not found" + } + } + }, + "post": { + "description": "Create a new dbt environment for a connection.", + "operationId": "connectionsDbtEnvironmentsCreate", + "summary": "Create dbt environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "dbt environment created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentItem" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection not found" + } + } + } + }, + "/api/v1/connections/{connectionId}/dbt/environments/{environmentId}": { + "put": { + "description": "Update an existing dbt environment for a connection.", + "operationId": "connectionsDbtEnvironmentsUpdate", + "summary": "Update dbt environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Environment ID", + "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + }, + "required": true, + "description": "Environment ID", + "name": "environmentId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "dbt environment updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentItem" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection or environment not found" + } + } + }, + "delete": { + "description": "Delete a dbt environment from a connection.", + "operationId": "connectionsDbtEnvironmentsDelete", + "summary": "Delete dbt environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Environment ID", + "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + }, + "required": true, + "description": "Environment ID", + "name": "environmentId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "dbt environment deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection or environment not found" + } + } + } + }, + "/api/v1/connections/{connectionId}/schedules": { + "get": { + "operationId": "connectionsSchedulesList", + "summary": "List schema refresh schedules", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "List of schema refresh schedules", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "schedules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Schema refresh schedule object", + "title": "ConnectionSchedule" + }, + "description": "List of schema refresh schedules" + } + }, + "required": [ + "schedules" + ], + "description": "List schedules response", + "title": "ConnectionsSchedulesListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "post": { + "operationId": "connectionsSchedulesCreate", + "summary": "Create schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hardRefresh": { + "type": "boolean", + "default": false, + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + } + }, + "required": [ + "schedule", + "timezone" + ], + "description": "Request body for creating a schema refresh schedule", + "title": "ConnectionsSchedulesCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Schema refresh schedule created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Created schedule response", + "title": "ConnectionsSchedulesCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid cron expression or timezone" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + } + }, + "/api/v1/connections/{connectionId}/schedules/{scheduleId}": { + "get": { + "operationId": "connectionsSchedulesGet", + "summary": "Get schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schema refresh schedule details", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Get schedule response", + "title": "ConnectionsSchedulesGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection or schedule not found" + } + } + }, + "put": { + "operationId": "connectionsSchedulesUpdate", + "summary": "Update schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hardRefresh": { + "type": "boolean", + "default": false, + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + } + }, + "required": [ + "schedule", + "timezone" + ], + "description": "Request body for updating a schema refresh schedule", + "title": "ConnectionsSchedulesUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Schema refresh schedule updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Updated schedule response", + "title": "ConnectionsSchedulesUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid cron expression or timezone" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection or schedule not found" + } + } + }, + "delete": { + "operationId": "connectionsSchedulesDelete", + "summary": "Delete schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schema refresh schedule deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "success" + ], + "description": "Delete schedule response", + "title": "ConnectionsSchedulesDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection or schedule not found" + } + } + } + }, + "/api/v1/connection-environments": { + "post": { + "operationId": "connectionEnvironmentsCreate", + "summary": "Create connection environments", + "tags": [ + "Connections" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "environmentConnectionIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "IDs of connections to use as environments", + "example": [ + "550e8400-e29b-41d4-a716-446655440002", + "550e8400-e29b-41d4-a716-446655440003" + ] + } + }, + "required": [ + "baseConnectionId", + "environmentConnectionIds" + ], + "description": "Request body for creating connection environments", + "title": "ConnectionsEnvironmentsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Connection environments created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionEnvironments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the environment connection", + "example": "550e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection environment identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } + }, + "required": [ + "baseConnectionId", + "connectionId", + "id", + "userAttributeValues" + ], + "description": "Connection environment object", + "title": "ConnectionEnvironment" + }, + "description": "Created connection environments" + } + }, + "required": [ + "connectionEnvironments" + ], + "description": "Create connection environments response", + "title": "ConnectionsEnvironmentsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or connection IDs" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "Base connection or environment connection not found" + } + } + } + }, + "/api/v1/connection-environments/{id}": { + "put": { + "operationId": "connectionEnvironmentsUpdate", + "summary": "Update connection environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection environment ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Connection environment ID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } + }, + "required": [ + "userAttributeValues" + ], + "description": "Request body for updating a connection environment", + "title": "ConnectionsEnvironmentsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Connection environment updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "success" + ], + "description": "Update connection environment response", + "title": "ConnectionsEnvironmentsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "Connection environment not found" + } + } + }, + "delete": { + "operationId": "connectionEnvironmentsDelete", + "summary": "Delete connection environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection environment ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Connection environment ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Connection environment deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "success" + ], + "description": "Delete connection environment response", + "title": "ConnectionsEnvironmentsDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "Connection environment not found" + } + } + } + }, + "/api/v1/content": { + "get": { + "operationId": "contentList", + "summary": "List content", + "tags": [ + "Content" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by creator user ID" + }, + "required": false, + "description": "Filter by creator user ID", + "name": "creatorId", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by folder ID (cannot be used with path)" + }, + "required": false, + "description": "Filter by folder ID (cannot be used with path)", + "name": "folderId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of fields to include (e.g., _count,labels)" + }, + "required": false, + "description": "Comma-separated list of fields to include (e.g., _count,labels)", + "name": "include", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by folder path (cannot be used with folderId)", + "example": "/reports/sales" + }, + "required": false, + "description": "Filter by folder path (cannot be used with folderId)", + "name": "path", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Filter by share scope", + "example": "organization" + }, + "required": false, + "description": "Filter by share scope", + "name": "scope", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction", + "example": "asc" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name", + "favorites" + ], + "description": "Field to sort by", + "example": "name" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of content (documents and folders)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentListResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters (cannot use both folderId and path)" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Folder not found (when filtering by path)" + } + } + } + }, + "/api/v1/dashboards/{identifier}/download": { + "post": { + "operationId": "dashboardsDownload", + "summary": "Initiate dashboard download", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardsDownloadBody" + } + } + } + }, + "responses": { + "200": { + "description": "Download job initiated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardsDownloadResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or filter configuration" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - cannot download this dashboard" + }, + "404": { + "description": "Dashboard not found" + }, + "409": { + "description": "Download already in progress for this dashboard" + }, + "500": { + "description": "Failed to initiate download" + } + } + } + }, + "/api/v1/dashboards/{identifier}/download/{jobId}": { + "get": { + "operationId": "dashboardsDownloadFile", + "summary": "Get download file", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Download job ID (UUID)", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Download job ID (UUID)", + "name": "jobId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "File ready - binary content streamed" + }, + "202": { + "description": "Download job still in progress" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Dashboard or download job not found" + }, + "410": { + "description": "Download job failed" + }, + "500": { + "description": "Failed to retrieve download artifact" + } + } + } + }, + "/api/v1/dashboards/{identifier}/download/{jobId}/status": { + "get": { + "operationId": "dashboardsDownloadStatus", + "summary": "Get download job status", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Download job ID (UUID)", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Download job ID (UUID)", + "name": "jobId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Download job status" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Dashboard or download job not found" + } + } + } + }, + "/api/v1/dashboards/{identifier}/filters": { + "get": { + "operationId": "dashboardsGetFilters", + "summary": "Get dashboard filters", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Dashboard filter and control configuration", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardFiltersResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - VIEWER role required" + }, + "404": { + "description": "Dashboard not found" + } + } + }, + "patch": { + "operationId": "dashboardsUpdateFilters", + "summary": "Update dashboard filters", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardsUpdateFiltersBody" + } + } + } + }, + "responses": { + "200": { + "description": "Filters updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardFiltersResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - must include at least one filter, control, or filterOrder" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - EDITOR role required" + }, + "404": { + "description": "Dashboard not found or document does not have a dashboard" + }, + "409": { + "description": "Conflict - draft already exists. Set clearExistingDraft to true to proceed." + } + } + } + }, + "/api/v1/documents": { + "get": { + "operationId": "documentsList", + "summary": "List documents", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by creator membership ID" + }, + "required": false, + "description": "Filter by creator membership ID", + "name": "creatorId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination" + }, + "required": false, + "description": "Cursor for pagination", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by folder ID" + }, + "required": false, + "description": "Filter by folder ID", + "name": "folderId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", + "example": "_count,labels" + }, + "required": false, + "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", + "name": "include", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of label names to filter by", + "example": "verified,important" + }, + "required": false, + "description": "Comma-separated list of label names to filter by", + "name": "labels", + "in": "query" + }, + { + "schema": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 50, + "description": "Number of records per page" + }, + "required": false, + "description": "Number of records per page", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name", + "favorites", + "updatedAt", + "visits" + ], + "default": "name", + "description": "Field to sort by" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter documents visible to this membership ID" + }, + "required": false, + "description": "Filter documents visible to this membership ID", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of documents", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + } + } + }, + "post": { + "operationId": "documentsCreate", + "summary": "Create document", + "tags": [ + "Documents" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Document created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or branch not found" + } + } + } + }, + "/api/v1/documents/{identifier}": { + "get": { + "description": "Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a document, modify the response, and PUT it back to update. Only dashboard documents are supported; analysis documents return 400.", + "operationId": "documentsGet", + "summary": "Get document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Document details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetResponse" + } + } + } + }, + "400": { + "description": "Analysis documents are not supported" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions to view the document" + }, + "404": { + "description": "Document not found" + } + } + }, + "put": { + "deprecated": true, + "description": "**Deprecated** \u2014 use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). Scheduled for removal on July 31, 2026 (see the `Sunset` response header).\n\nUpdates a document with the specified identifier. This endpoint performs a full resource replacement \u2014 all required fields must be provided and existing query presentations are replaced entirely. Only dashboard documents are supported; analysis documents and documents without an associated dashboard return 400. For published documents, the update goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", + "operationId": "documentsPut", + "summary": "Replace document (full replacement)", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsPutBody" + } + } + } + }, + "responses": { + "200": { + "description": "Document replaced successfully", + "headers": { + "Deprecation": { + "schema": { + "type": "string", + "enum": [ + "true" + ], + "description": "Marks the endpoint as deprecated." + }, + "required": true, + "description": "Marks the endpoint as deprecated." + }, + "Link": { + "schema": { + "type": "string", + "description": "Points to the v2 successor resource.", + "example": "; rel=\"successor-version\"" + }, + "required": true, + "description": "Points to the v2 successor resource." + }, + "Sunset": { + "schema": { + "type": "string", + "description": "Date the endpoint will be removed, in RFC 1123 form (RFC 8594).", + "example": "Fri, 31 Jul 2026 00:00:00 GMT" + }, + "required": true, + "description": "Date the endpoint will be removed, in RFC 1123 form (RFC 8594)." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsPutResponse" + } + } + } + }, + "400": { + "description": "Invalid request body, missing required fields, or validation error (also returned for analysis documents and documents without an associated dashboard)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions to update the document" + }, + "404": { + "description": "Document not found" + }, + "409": { + "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" + } + } + }, + "patch": { + "deprecated": true, + "description": "**Deprecated** \u2014 use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). Scheduled for removal on July 31, 2026 (see the `Sunset` response header).\n\nUpdates a document's name, description, and/or identifier. This is a partial update \u2014 only provided fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. When `identifier` is changed, the previous identifier is retained in the document identifier history and continues to redirect. For published documents, the update goes through a draft/publish workflow automatically.", + "operationId": "documentsUpdate", + "summary": "Rename document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Document updated successfully", + "headers": { + "Deprecation": { + "schema": { + "type": "string", + "enum": [ + "true" + ], + "description": "Marks the endpoint as deprecated." + }, + "required": true, + "description": "Marks the endpoint as deprecated." + }, + "Link": { + "schema": { + "type": "string", + "description": "Points to the v2 successor resource.", + "example": "; rel=\"successor-version\"" + }, + "required": true, + "description": "Points to the v2 successor resource." + }, + "Sunset": { + "schema": { + "type": "string", + "description": "Date the endpoint will be removed, in RFC 1123 form (RFC 8594).", + "example": "Fri, 31 Jul 2026 00:00:00 GMT" + }, + "required": true, + "description": "Date the endpoint will be removed, in RFC 1123 form (RFC 8594)." + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or validation error (e.g. missing name/description/identifier, name too long, identifier already in use)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - EDITOR role required" + }, + "404": { + "description": "Document not found" + }, + "409": { + "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" + } + } + }, + "delete": { + "operationId": "documentsDelete", + "summary": "Delete document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Document deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/queries": { + "get": { + "operationId": "documentsGetQueries", + "summary": "List document queries", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "List of queries in the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetQueriesResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/move": { + "put": { + "operationId": "documentsMove", + "summary": "Move document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsMoveBody" + } + } + } + }, + "responses": { + "200": { + "description": "Document moved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid folder path or scope" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document or folder not found" + } + } + } + }, + "/api/v1/documents/{identifier}/permissions": { + "get": { + "operationId": "documentsGetPermissions", + "summary": "Get document permissions", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "User membership ID to check permissions for" + }, + "required": true, + "description": "User membership ID to check permissions for", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "User permissions for the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetPermissionsResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document or user not found" + } + } + }, + "put": { + "operationId": "documentsUpdatePermissionSettings", + "summary": "Update document permission settings", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdatePermissionSettingsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permission settings updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document not found" + } + } + }, + "post": { + "operationId": "documentsAddPermits", + "summary": "Add document permits", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsAddPermitsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permissions added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document not found" + } + } + }, + "patch": { + "operationId": "documentsUpdatePermits", + "summary": "Update document permits", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdatePermitsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permissions updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document not found" + } + } + }, + "delete": { + "operationId": "documentsRevokePermits", + "summary": "Revoke document permits", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsRevokePermitsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permissions revoked successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/draft": { + "post": { + "operationId": "documentsCreateDraft", + "summary": "Create document draft", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateDraftBody" + } + } + } + }, + "responses": { + "200": { + "description": "Draft created or existing draft returned", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateDraftResponse" + } + } + } + }, + "400": { + "description": "Document is not eligible for publishing workflow" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - EDITOR role required" + }, + "404": { + "description": "Document or branch not found" + } + } + }, + "delete": { + "operationId": "documentsDiscardDraft", + "summary": "Discard document draft", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsDiscardDraftBody" + } + } + } + }, + "responses": { + "200": { + "description": "Draft discarded successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsDiscardDraftResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document or draft not found" + } + } + } + }, + "/api/v1/documents/{identifier}/drafts": { + "get": { + "description": "Lists drafts for a document with branch context. By default only active drafts are returned; pass `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by `createdAt` descending.", + "operationId": "documentsListDrafts", + "summary": "List document drafts", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized \u2014 when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", + "example": "archived" + }, + "required": false, + "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized \u2014 when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", + "name": "include", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of drafts for the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsListDraftsResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions to view the document" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/duplicate": { + "post": { + "operationId": "documentsDuplicate", + "summary": "Duplicate document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsDuplicateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Document duplicated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsDuplicateResponse" + } + } + } + }, + "400": { + "description": "Invalid name or folder path" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document or folder not found" + } + } + } + }, + "/api/v1/documents/{identifier}/upgrade": { + "post": { + "description": "Upgrades a document to the advanced dashboard layout (the \"File > Upgrade layout\" UI action). No-ops when the document already has advanced layout. For published documents the upgrade goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", + "operationId": "documentsUpgradeLayout", + "summary": "Upgrade dashboard layout", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpgradeLayoutBody" + } + } + } + }, + "responses": { + "200": { + "description": "Layout upgraded, or no-op if the document already had advanced layout", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpgradeLayoutResponse" + } + } + } + }, + "400": { + "description": "Document does not have a dashboard to upgrade" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + }, + "409": { + "description": "A draft already exists for the published document; set clearExistingDraft to override" + } + } + } + }, + "/api/v1/documents/{identifier}/favorite": { + "put": { + "operationId": "documentsAddFavorite", + "summary": "Add document to favorites", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Favorite added successfully" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + } + } + }, + "delete": { + "operationId": "documentsRemoveFavorite", + "summary": "Remove document from favorites", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Favorite removed successfully" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/labels": { + "patch": { + "operationId": "documentsBulkUpdateLabels", + "summary": "Bulk update document labels", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Labels updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsResponse" + } + } + } + }, + "400": { + "description": "Invalid request - at least one label must be specified" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/labels/{labelName}": { + "put": { + "operationId": "documentsAddLabel", + "summary": "Add label to document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier", + "example": "abc123" + }, + "required": true, + "description": "Document identifier", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "labelName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Label added successfully" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document or label not found" + } + } + }, + "delete": { + "operationId": "documentsRemoveLabel", + "summary": "Remove label from document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier", + "example": "abc123" + }, + "required": true, + "description": "Document identifier", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "labelName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Label removed successfully" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/transfer-ownership": { + "put": { + "operationId": "documentsTransferOwnership", + "summary": "Transfer document ownership", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsTransferOwnershipBody" + } + } + } + }, + "responses": { + "200": { + "description": "Ownership transferred successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid user ID" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role or owner required" + }, + "404": { + "description": "Document or user not found" + } + } + } + }, + "/api/v1/documents/{identifier}/access-list": { + "get": { + "operationId": "documentsAccessList", + "summary": "List document access principals", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction (default: asc)", + "example": "desc" + }, + "required": false, + "description": "Sort direction (default: asc)", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Field to sort results by" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "direct", + "folder" + ], + "description": "Filter by access source: direct or folder" + }, + "required": false, + "description": "Filter by access source: direct or folder", + "name": "accessSource", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "user", + "userGroup" + ], + "description": "Filter by principal type: user or userGroup" + }, + "required": false, + "description": "Filter by principal type: user or userGroup", + "name": "type", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of users and groups with access", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsAccessListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - VIEWER role required" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/favorites": { + "get": { + "description": "Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need to preserve favorites when replacing documents, without iterating every user in the organization.", + "operationId": "documentsListFavorites", + "summary": "List users who favorited the document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction by favoritedAt (default: asc \u2014 oldest first)", + "example": "desc" + }, + "required": false, + "description": "Sort direction by favoritedAt (default: asc \u2014 oldest first)", + "name": "sortDirection", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of users who favorited the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsListFavoritesResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied \u2014 caller lacks MANAGER on the document, or used a user-scoped (personal access token) API key (org-scoped only)" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v2/documents": { + "post": { + "description": "Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body \u2014 `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed.\n\nWhen `containers` is omitted, every dashboard-eligible tile is auto-placed in a default layout. When `containers` is present, it fully defines the layout \u2014 tiles it does not reference are stored but not rendered. Send `containers: null` to create a workbook-only document with no dashboard (`controls` and `settings` must then be omitted); an empty `containers: []` is rejected.\n\nThe new document is published live before the response returns. As a first publish of brand-new content it is not subject to the org\u2019s `requirePullRequestToPublish` policy (which gates edits to existing content).", + "operationId": "documentsV2Create", + "summary": "Create document", + "tags": [ + "Documents" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2CreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Document created and published successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2CreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded), or the `identifier` is already in use." + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to create a document on this model." + }, + "404": { + "description": "Base model or branch not found." + }, + "405": { + "description": "Method not allowed." + } + } + } + }, + "/api/v2/documents/{identifier}": { + "get": { + "description": "Read the document's published state \u2014 draft edits are never surfaced here. When a draft exists, read it via `GET /api/v2/documents/{identifier}/draft/{draftIdentifier}` before round-tripping the response into a draft PATCH, so you patch the draft's own content rather than published content over it. Returns the full `DocumentsV2ReadResponse` shape.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) \u2014 the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", + "operationId": "documentsV2Get", + "summary": "Read document state", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "example": "abc123" + }, + "required": true, + "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "0", + "1", + "true", + "false" + ], + "description": "Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless." + }, + "required": false, + "description": "Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless.", + "name": "pretty", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Document state. A workbook-only document (no dashboard layout yet) returns only the workbook-scoped fields (`name`, `description`, `queryPresentations`); the dashboard-scoped `containers`, `controls`, and `settings` are omitted until a layout exists.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2ReadResponse" + } + } + } + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to read the document." + }, + "404": { + "description": "Document not found." + }, + "422": { + "description": "The document cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." + } + } + } + }, + "/api/v2/documents/{identifier}/draft": { + "patch": { + "description": "Create a new draft on the published document and apply the patch. No auto-publish \u2014 the response includes the new `draftIdentifier` for follow-up calls.\n\nPass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main (unpublished) workspace.", + "operationId": "documentsV2PatchDraft", + "summary": "Create draft and patch document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "example": "abc123" + }, + "required": true, + "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2CreateDraftBody" + } + } + } + }, + "responses": { + "200": { + "description": "Draft created and patch applied successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded, or a `modelId` that differs from the document\u2019s immutable base model)." + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to update the document." + }, + "404": { + "description": "Document or branch not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document \u2014 retry." + }, + "422": { + "description": "The document cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only document patched without a `containers` payload (or with an empty one)." + } + } + } + }, + "/api/v2/documents/{identifier}/draft/{draftIdentifier}": { + "get": { + "description": "Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape \u2014 same as the live-state read endpoint.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) \u2014 the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", + "operationId": "documentsV2GetDraft", + "summary": "Read draft state", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "example": "def456" + }, + "required": true, + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "name": "draftIdentifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Published document identifier.", + "example": "abc123" + }, + "required": true, + "description": "Published document identifier.", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "0", + "1", + "true", + "false" + ], + "description": "Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless." + }, + "required": false, + "description": "Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless.", + "name": "pretty", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Draft state.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2ReadResponse" + } + } + } + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to read the draft." + }, + "404": { + "description": "Document or draft not found." + }, + "422": { + "description": "The draft cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." + } + } + }, + "patch": { + "description": "Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply \u2014 no draft creation, no publish.", + "operationId": "documentsV2PatchDraftByIdentifier", + "summary": "Patch draft", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "example": "def456" + }, + "required": true, + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "name": "draftIdentifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Published document identifier.", + "example": "abc123" + }, + "required": true, + "description": "Published document identifier.", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" + } + } + } + }, + "responses": { + "200": { + "description": "Patch applied to draft successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded, or a `modelId` that differs from the document\u2019s immutable base model)." + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to update the draft." + }, + "404": { + "description": "Document or draft not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document \u2014 retry." + }, + "422": { + "description": "The draft cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only draft patched without a `containers` payload (or with an empty one)." + } + } + } + }, + "/api/v2/documents/{identifier}/draft/publish": { + "post": { + "description": "Publish the document's current main (non-branch) draft, promoting it to the published version. No request body \u2014 the draft is consumed, so the response echoes the now-published document metadata.\n\nOnly the main draft is publishable here; a branch-attached draft is published by merging its branch (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft returns 404. Documents that require a pull request to publish return 400.", + "operationId": "documentsV2PublishDraft", + "summary": "Publish draft", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "example": "abc123" + }, + "required": true, + "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Draft published successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PublishDraftResponse" + } + } + } + }, + "400": { + "description": "The document requires a pull request to publish (response detail: \"Can't publish because this document can only be edited through a branch\")." + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to publish the draft." + }, + "404": { + "description": "Document not found, or it has no main draft to publish (a branch-attached draft is published by merging its branch)." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document." + } + } + } + }, + "/api/v2/documents/{identifier}/identifier": { + "put": { + "description": "Rename a published document's identifier. The change is applied live and immediately \u2014 it does not go through the draft/publish workflow \u2014 and the former identifier is recorded in the document's rename history.\n\nOnly published documents can be renamed. A draft target returns 409; an unknown or archived target returns 404. The new identifier must be a valid slug (otherwise 400) and unused by any other document in the organization (otherwise 409).", + "operationId": "documentsV2UpdateIdentifier", + "summary": "Rename document identifier", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "example": "abc123" + }, + "required": true, + "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", + "name": "identifier", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2UpdateIdentifierBody" + } + } + } + }, + "responses": { + "200": { + "description": "Identifier updated successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2UpdateIdentifierResponse" + } + } + } + }, + "400": { + "description": "Invalid identifier format." + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to rename the document." + }, + "404": { + "description": "Document not found or archived." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is a draft rather than a published document, or the requested identifier is already in use by another document." + } + } + } + }, + "/api/v1/embed/sso/generate-session": { + "post": { + "operationId": "embedSsoGenerateSession", + "summary": "Generate embedded SSO session", + "tags": [ + "Embed" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbedSsoGenerateSessionBody" + } + } + } + }, + "responses": { + "200": { + "description": "Session token generated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbedSsoGenerateSessionResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required (API key with embed scope)" + }, + "403": { + "description": "Permission denied - embed not enabled" + } + } + } + }, + "/api/v1/ai/eval/prompt-sets": { + "get": { + "description": "List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt sets for every shared model the caller can access. Requires at least the Querier role on each requested model.", + "operationId": "aiEvalPromptSetsList", + "summary": "List eval prompt sets", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ], + "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "example": "false" + }, + "required": false, + "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "name": "archived", + "in": "query" + }, + { + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`)." + }, + "required": false, + "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`).", + "name": "model_ids", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of prompt sets, sorted alphabetically by name.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsListResponse" + } + } + } + }, + "400": { + "description": "Invalid query params (e.g. `model_ids` contains a non-UUID, or `archived` is not `true`/`false`).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. The caller must have at least the Querier role on each requested model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "No eval-accessible models for this caller.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + }, + "post": { + "description": "Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional prompts can be added later via PATCH.", + "operationId": "aiEvalPromptSetsCreate", + "summary": "Create an eval prompt set", + "tags": [ + "AI Eval" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Prompt set created successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. The caller must have at least the Querier role on the model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "422": { + "description": "Prompt count exceeds the organization's per-set cap (default 25, higher for orgs with the `ai-eval-extra-prompts` flag).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError422" + } + } + } + } + } + } + }, + "/api/v1/ai/eval/prompt-sets/{promptSetId}": { + "get": { + "description": "Get a single prompt set with all of its prompts.", + "operationId": "aiEvalPromptSetsGet", + "summary": "Get an eval prompt set", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Prompt set details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsGetResponse" + } + } + } + }, + "400": { + "description": "Invalid `promptSetId` \u2014 must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + }, + "patch": { + "description": "Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully replaces the existing list \u2014 existing prompts omitted from the list are deleted, entries without an `id` are created, and entries with a matching `id` are updated in place.", + "operationId": "aiEvalPromptSetsUpdate", + "summary": "Update an eval prompt set", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Prompt set updated successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "422": { + "description": "A `prompts[].id` in the request does not belong to this prompt set, or the prompt count exceeds the organization's per-set cap (default 25, higher for orgs with the `ai-eval-extra-prompts` flag).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError422" + } + } + } + } + } + }, + "delete": { + "description": "Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight agentic job associated with the set; the returned `cancelled_job_count` reports how many were cancelled. The archive is committed before run cancellations start. Cancellation is best-effort \u2014 the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt set is already archived. The call is idempotent \u2014 retrying drains any remaining runs.", + "operationId": "aiEvalPromptSetsArchive", + "summary": "Archive an eval prompt set", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Prompt set archived successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsDeleteResponse" + } + } + } + }, + "400": { + "description": "Invalid `promptSetId` \u2014 must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "500": { + "description": "Archive committed but a run-cancellation failed; the set is already archived \u2014 safe to retry.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } + } + } + } + }, + "/api/v1/ai/eval/prompt-sets/{promptSetId}/unarchive": { + "post": { + "description": "Restore an archived prompt set.", + "operationId": "aiEvalPromptSetsUnarchive", + "summary": "Restore an archived eval prompt set", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Prompt set restored successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsUnarchiveResponse" + } + } + } + }, + "400": { + "description": "Invalid `promptSetId` \u2014 must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/eval/runs": { + "get": { + "description": "List runs for a prompt set, newest first, filtered to runs whose model the caller can access. The `prompt_set_id` query parameter is required.", + "operationId": "aiEvalRunsList", + "summary": "List eval runs", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ], + "description": "When `true`, returns archived runs instead of active ones. Defaults to `false`.", + "example": "false" + }, + "required": false, + "description": "When `true`, returns archived runs instead of active ones. Defaults to `false`.", + "name": "archived", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Required \u2014 the prompt set whose runs should be listed.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Required \u2014 the prompt set whose runs should be listed.", + "name": "prompt_set_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of runs for the prompt set.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsListResponse" + } + } + } + }, + "400": { + "description": "Missing or invalid `prompt_set_id`.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + }, + "post": { + "description": "Create and start a new run against an existing prompt set. The run enqueues one agentic job per prompt and begins executing immediately. Returns the newly created run with its initial per-prompt result rows.", + "operationId": "aiEvalRunsCreate", + "summary": "Start an eval run", + "tags": [ + "AI Eval" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Run created and jobs enqueued.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. The caller must have at least the Querier role on the prompt set's model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "The prompt set was not found, or `run_config.branch_id` does not match an existing branch in the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "422": { + "description": "`run_config.branch_id` does not belong to the prompt set's model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError422" + } + } + } + }, + "429": { + "description": "Per-user active-run cap reached.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError429" + } + } + } + }, + "500": { + "description": "Run created and jobs enqueued, but it could not be re-read for the response. The run exists \u2014 list runs for the prompt set to find it rather than retrying, since a retry starts a duplicate run.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } + }, + "503": { + "description": "AI eval is paused for this organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError503" + } + } + } + } + } + } + }, + "/api/v1/ai/eval/runs/{runId}": { + "get": { + "description": "Get an eval run with every per-prompt result row, including the underlying agentic job state and any scoring data.", + "operationId": "aiEvalRunsGet", + "summary": "Get an eval run", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "The unique identifier of the eval run.", + "name": "runId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Run detail.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsGetResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Run not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + }, + "delete": { + "description": "Archive (soft-delete) an eval run. Any non-terminal per-prompt agentic jobs are cancelled as part of the archive (best-effort), and a still-RUNNING run is flipped to CANCELLED before archival. The call is idempotent; archiving an already-terminal or already-archived run is a no-op.", + "operationId": "aiEvalRunsArchive", + "summary": "Archive an eval run", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "The unique identifier of the eval run.", + "name": "runId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Run archived successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsDeleteResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Run not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "500": { + "description": "A still-running run may already be flipped to CANCELLED and archived even though the rest of the cascade failed \u2014 safe to retry.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } + } + } + } + }, + "/api/v1/ai/eval/runs/{runId}/cancel": { + "post": { + "description": "Cancel an in-flight eval run. Any non-terminal per-prompt jobs are cancelled and the run is archived \u2014 the response returns the updated run inline (`status: CANCELLED`, `is_archived: true`); use `/unarchive` to surface it in the default `archived=false` list again.", + "operationId": "aiEvalRunsCancel", + "summary": "Cancel an eval run", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "The unique identifier of the eval run.", + "name": "runId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Cancellation processed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsCancelResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Run not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "500": { + "description": "The run was cancelled and archived, but could not be re-read for the response \u2014 safe to retry.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } + } + } + } + }, + "/api/v1/ai/eval/runs/{runId}/unarchive": { + "post": { + "description": "Restore an archived eval run.", + "operationId": "aiEvalRunsUnarchive", + "summary": "Restore an archived eval run", + "tags": [ + "AI Eval" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "The unique identifier of the eval run.", + "name": "runId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Run restored successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalRunsUnarchiveResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Run not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + } + }, + "/api/v1/folders": { + "get": { + "operationId": "foldersList", + "summary": "List folders", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination" + }, + "required": false, + "description": "Cursor for pagination", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of fields to include (_count, labels, onlySharedWithMe). onlySharedWithMe returns only folders shared with the user, cannot be combined with ownerId or path, and when used with org-scoped API keys requires the userId query parameter. For user-scoped keys (PAT), userId is auto-inferred from the token.", + "example": "_count,labels" + }, + "required": false, + "description": "Comma-separated list of fields to include (_count, labels, onlySharedWithMe). onlySharedWithMe returns only folders shared with the user, cannot be combined with ownerId or path, and when used with org-scoped API keys requires the userId query parameter. For user-scoped keys (PAT), userId is auto-inferred from the token.", + "name": "include", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of labels to filter by" + }, + "required": false, + "description": "Comma-separated list of labels to filter by", + "name": "labels", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by owner user ID" + }, + "required": false, + "description": "Filter by owner user ID", + "name": "ownerId", + "in": "query" + }, + { + "schema": { + "type": [ + "number", + "null" + ], + "description": "Number of results per page", + "example": 20 + }, + "required": false, + "description": "Number of results per page", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by exact path" + }, + "required": false, + "description": "Filter by exact path", + "name": "path", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Filter by share scope" + }, + "required": false, + "description": "Filter by share scope", + "name": "scope", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name", + "createdAt", + "updatedAt", + "favorites", + "path" + ], + "description": "Field to sort by" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "User membership ID. Only used with onlySharedWithMe include field. Required for org-scoped API keys; auto-inferred from the token for user-scoped keys (PAT)." + }, + "required": false, + "description": "User membership ID. Only used with onlySharedWithMe include field. Required for org-scoped API keys; auto-inferred from the token for user-scoped keys (PAT).", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of folders", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Folder not found (when filtering by path)" + } + } + }, + "post": { + "operationId": "foldersCreate", + "summary": "Create a folder", + "tags": [ + "Folders" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Folder created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body, scope mismatch with parent folder, or cannot create under restricted folder owned by another user" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Parent folder not found" + } + } + } + }, + "/api/v1/folders/{folderId}": { + "delete": { + "description": "Deletes a folder. By default, non-empty folders (containing documents or sub-folders) return a 400 error. Pass `force=true` to recursively archive all documents (soft-delete to trash) and permanently remove all sub-folders before deleting the target folder. Force delete is limited to 100 total items (documents + sub-folders).", + "operationId": "foldersDelete", + "summary": "Delete a folder", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the folder", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Unique identifier for the folder", + "name": "folderId", + "in": "path" + }, + { + "schema": { + "type": [ + "boolean", + "null" + ], + "default": false, + "description": "When true, recursively deletes all documents (sent to trash) and sub-folders within the folder. Limited to 100 total items (documents + sub-folders)." + }, + "required": false, + "description": "When true, recursively deletes all documents (sent to trash) and sub-folders within the folder. Limited to 100 total items (documents + sub-folders).", + "name": "force", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Folder deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersDeleteResponse" + } + } + } + }, + "400": { + "description": "Folder cannot be deleted (e.g., contains documents or sub-folders and force is not set, or force delete exceeds the 100-item limit)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - cannot view or delete folder" + }, + "404": { + "description": "Folder not found" + } + } + }, + "patch": { + "description": "Update a folder's display name and/or URL path segment. At least one of `name` or `path` must be provided. Changing the name does not automatically update the path. When the path is updated, descendant folder paths are cascaded.", + "operationId": "foldersUpdate", + "summary": "Update a folder", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the folder", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Unique identifier for the folder", + "name": "folderId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Folder updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body (empty name, invalid path characters, reserved path, or neither field provided)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - EDITOR role required" + }, + "404": { + "description": "Folder not found" + }, + "409": { + "description": "Path conflicts with an existing folder (when resolvePathConflict is false)" + } + } + } + }, + "/api/v1/folders/{folderId}/permissions": { + "get": { + "operationId": "foldersGetPermissions", + "summary": "Get folder permissions", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the folder", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Unique identifier for the folder", + "name": "folderId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter permits for a specific user. If omitted, returns all permits (requires MANAGER role)." + }, + "required": false, + "description": "Filter permits for a specific user. If omitted, returns all permits (requires MANAGER role).", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Folder permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersGetPermissionsResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - VIEWER role required to view specific user permissions, MANAGER role required to list all" + }, + "404": { + "description": "Folder or user not found" + } + } + }, + "post": { + "operationId": "foldersAddPermissions", + "summary": "Add folder permissions", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the folder", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Unique identifier for the folder", + "name": "folderId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersAddPermissionsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permissions added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersAddPermissionsResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds must be provided" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Folder not found" + } + } + }, + "patch": { + "operationId": "foldersUpdatePermissions", + "summary": "Update folder permissions", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the folder", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Unique identifier for the folder", + "name": "folderId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersUpdatePermissionsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permissions updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersUpdatePermissionsResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds must be provided" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Folder not found" + } + } + }, + "delete": { + "operationId": "foldersRevokePermissions", + "summary": "Revoke folder permissions", + "tags": [ + "Folders" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the folder", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Unique identifier for the folder", + "name": "folderId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersRevokePermissionsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permissions revoked successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FoldersRevokePermissionsResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds must be provided" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Folder not found" + } + } + } + }, + "/api/v1/labels": { + "get": { + "operationId": "labelsList", + "summary": "List all labels", + "tags": [ + "Labels" + ], + "responses": { + "200": { + "description": "List of all labels in the organization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + } + } + }, + "post": { + "operationId": "labelsCreate", + "summary": "Create a label", + "tags": [ + "Labels" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Label created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - cannot create verified/homepage labels without admin permissions" + }, + "409": { + "description": "Label with this name already exists" + } + } + } + }, + "/api/v1/labels/{name}": { + "get": { + "operationId": "labelsGet", + "summary": "Get a label by name", + "tags": [ + "Labels" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "name", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Label details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Label not found" + } + } + }, + "put": { + "operationId": "labelsUpdate", + "summary": "Update a label", + "tags": [ + "Labels" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "name", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Label updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LabelsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - cannot modify verified/homepage labels without admin permissions" + }, + "404": { + "description": "Label not found" + }, + "409": { + "description": "Label with new name already exists" + } + } + }, + "delete": { + "operationId": "labelsDelete", + "summary": "Delete a label", + "tags": [ + "Labels" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "name", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Label deleted successfully" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - cannot delete verified/homepage labels without admin permissions" + }, + "404": { + "description": "Label not found" + }, + "409": { + "description": "Cannot delete label that is applied to documents" + } + } + } + }, + "/api/v1/models/{modelId}/suggestions": { + "get": { + "description": "Lists AI-generated model suggestions for a shared model, filtered by dismissal status. Requires organization admin permissions.", + "operationId": "modelSuggestionsList", + "summary": "List model suggestions", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestions belong to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestions belong to", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Cursor for pagination: the `nextCursor` from the previous response (the last suggestion id)." + }, + "required": false, + "description": "Cursor for pagination: the `nextCursor` from the previous response (the last suggestion id).", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "active", + "ignored", + "all" + ], + "default": "active", + "description": "Which suggestions to return: `active` (default, not dismissed), `ignored` (dismissed only), or `all`.", + "example": "active" + }, + "required": false, + "description": "Which suggestions to return: `active` (default, not dismissed), `ignored` (dismissed only), or `all`.", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of suggestions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelSuggestionsListResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters or malformed `modelId`" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Model not found in this organization" + } + } + } + }, + "/api/v1/models/{modelId}/suggestions/schedule": { + "put": { + "description": "Enables the daily schedule that generates suggestions for the shared model. Idempotent \u2014 re-enabling leaves an existing schedule untouched. Requires organization admin permissions.", + "operationId": "modelSuggestionsScheduleEnable", + "summary": "Enable the suggestion schedule", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestions belong to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestions belong to", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScheduleSuggestionsBody" + } + } + } + }, + "responses": { + "200": { + "description": "The schedule is enabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScheduleSuggestionsResponse" + } + } + } + }, + "400": { + "description": "Invalid timezone or malformed `modelId`" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Model not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + }, + "delete": { + "description": "Disables the daily generation schedule for the shared model. Idempotent. Requires organization admin permissions.", + "operationId": "modelSuggestionsScheduleDisable", + "summary": "Disable the suggestion schedule", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestions belong to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestions belong to", + "name": "modelId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The schedule is disabled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Malformed `modelId`" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Model not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + } + }, + "/api/v1/models/{modelId}/suggestions/{suggestionId}/ignore": { + "post": { + "description": "Dismisses (ignores) a suggestion, optionally with a reason. Requires organization admin permissions.", + "operationId": "modelSuggestionsIgnore", + "summary": "Ignore a suggestion", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestion belongs to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestion belongs to", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the suggestion", + "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" + }, + "required": true, + "description": "UUID of the suggestion", + "name": "suggestionId", + "in": "path" + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IgnoreSuggestionBody" + } + } + } + }, + "responses": { + "200": { + "description": "The suggestion was dismissed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid body or malformed id" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Suggestion or model not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + } + }, + "/api/v1/models/{modelId}/suggestions/{suggestionId}/restore": { + "post": { + "description": "Restores a previously dismissed suggestion back to the active list. Requires organization admin permissions.", + "operationId": "modelSuggestionsRestore", + "summary": "Restore a suggestion", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestion belongs to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestion belongs to", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the suggestion", + "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" + }, + "required": true, + "description": "UUID of the suggestion", + "name": "suggestionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The suggestion was restored", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Malformed id" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Suggestion or model not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + } + }, + "/api/v1/models/{modelId}/suggestions/{suggestionId}": { + "delete": { + "description": "Permanently deletes a suggestion. Requires organization admin permissions.", + "operationId": "modelSuggestionsDelete", + "summary": "Delete a suggestion", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestion belongs to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestion belongs to", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the suggestion", + "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" + }, + "required": true, + "description": "UUID of the suggestion", + "name": "suggestionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The suggestion was deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Malformed id" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Suggestion or model not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + } + }, + "/api/v1/models": { + "get": { + "operationId": "modelsList", + "summary": "List models", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by base model ID" + }, + "required": false, + "description": "Filter by base model ID", + "name": "baseModelId", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by connection ID" + }, + "required": false, + "description": "Filter by connection ID", + "name": "connectionId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination" + }, + "required": false, + "description": "Cursor for pagination", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of fields to include (e.g., activeBranches)", + "example": "activeBranches" + }, + "required": false, + "description": "Comma-separated list of fields to include (e.g., activeBranches)", + "name": "include", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "0", + "1", + "true", + "false" + ], + "description": "Include deleted models" + }, + "required": false, + "description": "Include deleted models", + "name": "includeDeleted", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by specific model ID" + }, + "required": false, + "description": "Filter by specific model ID", + "name": "modelId", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "SCHEMA", + "SHARED", + "SHARED_EXTENSION", + "BRANCH", + "WORKBOOK", + "QUERY" + ], + "description": "Filter by model kind" + }, + "required": false, + "description": "Filter by model kind", + "name": "modelKind", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by model name" + }, + "required": false, + "description": "Filter by model name", + "name": "name", + "in": "query" + }, + { + "schema": { + "type": "integer", + "exclusiveMinimum": 0, + "description": "Number of results per page", + "example": 20 + }, + "required": false, + "description": "Number of results per page", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name", + "modelKind", + "connectionId", + "baseModelId", + "createdAt", + "updatedAt" + ], + "description": "Field to sort by" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of models", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + } + } + }, + "post": { + "description": "Create a new model. Supports creating schema, shared, branch, and shared_extension models.", + "operationId": "modelsCreate", + "summary": "Create model", + "tags": [ + "Models" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateModelSchemaBase" + } + } + } + }, + "responses": { + "200": { + "description": "Model created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "Error message if creation failed" + }, + "message": { + "type": "string", + "description": "Additional message" + }, + "model": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Created model ID" + }, + "modelKind": { + "type": "string", + "description": "Kind of model created" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Model name" + } + }, + "required": [ + "id", + "modelKind", + "name" + ], + "description": "Created model details" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + } + }, + "required": [ + "success" + ], + "description": "Create model response", + "title": "ModelsCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or model creation not allowed" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Connection or base model not found" + } + } + } + }, + "/api/v1/models/{modelId}": { + "patch": { + "description": "Update metadata for an existing model. Currently supports renaming the model via the `name` field.", + "operationId": "modelsUpdate", + "summary": "Update model", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Model updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/jobs/{jobId}/status": { + "get": { + "description": "Check status of a schema refresh job (POST /api/v1/models/{modelId}/refresh) or a dbt sync job (POST /api/v1/models/{modelId}/dbt-sync). Returns IN_PROGRESS, COMPLETED, or FAILED.", + "operationId": "jobsGetStatus", + "summary": "Get schema refresh or dbt sync job status", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "The job ID returned from a job creation endpoint (e.g., POST /api/v1/models/{modelId}/refresh)", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "The job ID returned from a job creation endpoint (e.g., POST /api/v1/models/{modelId}/refresh)", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Job status (IN_PROGRESS, COMPLETED, or FAILED)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JobsGetStatusResponse" + } + } + } + }, + "400": { + "description": "Unsupported job type (only schema refresh and dbt sync supported)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection READ permission required" + }, + "404": { + "description": "Job not found" + } + } + } + }, + "/api/v1/models/{modelId}/schemas": { + "get": { + "operationId": "modelsGetSchemas", + "summary": "List available schemas for a model", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of available schemas", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGetSchemasResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/view": { + "get": { + "operationId": "modelsGetViews", + "summary": "Get model views", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of views in the model", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGetViewResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/view/{viewName}": { + "patch": { + "operationId": "modelsUpdateView", + "summary": "Update view", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "View name", + "example": "orders" + }, + "required": true, + "description": "View name", + "name": "viewName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsUpdateViewBody" + } + } + } + }, + "responses": { + "200": { + "description": "View updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or view not found" + } + } + }, + "delete": { + "operationId": "modelsDeleteView", + "summary": "Delete view", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "View name", + "example": "orders" + }, + "required": true, + "description": "View name", + "name": "viewName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "COMBINED", + "MERGED", + "EXTENSION" + ], + "description": "Controls delete behavior to match IDE editing modes. COMBINED (default) marks the view as ignored if it exists in the parent model, otherwise hard-deletes. MERGED marks the view as shallowIgnored (hidden only from the immediate parent). EXTENSION hard-deletes the view from the extension layer.", + "example": "COMBINED" + }, + "required": false, + "description": "Controls delete behavior to match IDE editing modes. COMBINED (default) marks the view as ignored if it exists in the parent model, otherwise hard-deletes. MERGED marks the view as shallowIgnored (hidden only from the immediate parent). EXTENSION hard-deletes the view from the extension layer.", + "name": "mode", + "in": "query" + } + ], + "responses": { + "200": { + "description": "View deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or view not found" + } + } + } + }, + "/api/v1/models/{modelId}/view/{viewName}/field/{fieldName}": { + "patch": { + "operationId": "modelsUpdateField", + "summary": "Update field", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "View name", + "example": "orders" + }, + "required": true, + "description": "View name", + "name": "viewName", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Field name", + "example": "total_amount" + }, + "required": true, + "description": "Field name", + "name": "fieldName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsUpdateFieldBody" + } + } + } + }, + "responses": { + "200": { + "description": "Field updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model, view, or field not found" + } + } + }, + "delete": { + "operationId": "modelsDeleteField", + "summary": "Delete field", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "View name", + "example": "orders" + }, + "required": true, + "description": "View name", + "name": "viewName", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Field name", + "example": "total_amount" + }, + "required": true, + "description": "Field name", + "name": "fieldName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID" + }, + "required": false, + "description": "Branch ID", + "name": "branch_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Topic context for the field" + }, + "required": false, + "description": "Topic context for the field", + "name": "topic_context", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Field deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model, view, or field not found" + } + } + } + }, + "/api/v1/models/{modelId}/topic": { + "get": { + "operationId": "modelsListTopics", + "summary": "List topics", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of topics in the model", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsListTopicsResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/topic/{topicName}": { + "get": { + "operationId": "modelsGetTopic", + "summary": "Get topic", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Topic name", + "example": "sales_analytics" + }, + "required": true, + "description": "Topic name", + "name": "topicName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Topic details with relationships and views", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGetTopicResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or topic not found" + } + } + }, + "patch": { + "operationId": "modelsUpdateTopic", + "summary": "Update topic", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Topic name", + "example": "sales_analytics" + }, + "required": true, + "description": "Topic name", + "name": "topicName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsUpdateTopicBody" + } + } + } + }, + "responses": { + "200": { + "description": "Topic updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or topic not found" + } + } + }, + "delete": { + "operationId": "modelsDeleteTopic", + "summary": "Delete topic", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Topic name", + "example": "sales_analytics" + }, + "required": true, + "description": "Topic name", + "name": "topicName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "COMBINED", + "MERGED", + "EXTENSION" + ], + "description": "Controls delete behavior to match IDE editing modes. COMBINED (default) adds the topic to deletedTopics if it exists in the parent model (prevents reappearing). MERGED behaves the same as COMBINED. EXTENSION hard-deletes the topic from the extension layer.", + "example": "COMBINED" + }, + "required": false, + "description": "Controls delete behavior to match IDE editing modes. COMBINED (default) adds the topic to deletedTopics if it exists in the parent model (prevents reappearing). MERGED behaves the same as COMBINED. EXTENSION hard-deletes the topic from the extension layer.", + "name": "mode", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Topic deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or topic not found" + } + } + } + }, + "/api/v1/models/{modelId}/field": { + "post": { + "operationId": "modelsCreateField", + "summary": "Create field", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsCreateFieldBody" + } + } + } + }, + "responses": { + "201": { + "description": "Field created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or view not found" + } + } + } + }, + "/api/v1/models/{modelId}/refresh": { + "post": { + "operationId": "modelsRefresh", + "summary": "Refresh model schema", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID for branch-based schema refresh. Required when branch-based schema refresh is enabled for the connection. Must not be provided when branch-based schema refresh is not enabled.", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID for branch-based schema refresh. Required when branch-based schema refresh is enabled for the connection. Must not be provided when branch-based schema refresh is not enabled.", + "name": "branch_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ], + "description": "When true (the default), performs a hard refresh that fully discards and rebuilds the schema model. When false, performs a soft refresh that merges newly generated views with the existing model. Must be set to false when `schemas` or `tables` filters are provided.", + "example": "false" + }, + "required": false, + "description": "When true (the default), performs a hard refresh that fully discards and rebuilds the schema model. When false, performs a soft refresh that merges newly generated views with the existing model. Must be set to false when `schemas` or `tables` filters are provided.", + "name": "hard_refresh", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Optional comma-separated list of schemas to refresh selectively. Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "example": "public,analytics" + }, + "required": false, + "description": "Optional comma-separated list of schemas to refresh selectively. Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "name": "schemas", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Optional comma-separated list of tables to refresh selectively. Only the listed tables are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "example": "public.orders,public.customers" + }, + "required": false, + "description": "Optional comma-separated list of tables to refresh selectively. Only the listed tables are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "name": "tables", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Refresh job started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsRefreshResponse" + } + } + } + }, + "400": { + "description": "Bad request - branch_id required when branch-based schema refresh is enabled, branch_id not allowed when it is not enabled, or hard refresh requested with selective schemas/tables filters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/validate": { + "get": { + "operationId": "modelsValidate", + "summary": "Validate model", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to validate" + }, + "required": false, + "description": "Branch ID to validate", + "name": "branchId", + "in": "query" + }, + { + "schema": { + "type": "integer", + "exclusiveMinimum": 0, + "description": "Maximum number of validation issues to return" + }, + "required": false, + "description": "Maximum number of validation issues to return", + "name": "limit", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Validation results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsValidateResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/migrate": { + "post": { + "operationId": "modelsMigrate", + "summary": "Migrate model", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsMigrateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Migration completed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or migration not allowed" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/branch/{branchName}": { + "delete": { + "operationId": "modelsDeleteBranch", + "summary": "Delete branch", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Branch name", + "example": "feature/new-metrics" + }, + "required": true, + "description": "Branch name", + "name": "branchName", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Branch deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or branch not found" + } + } + } + }, + "/api/v1/models/{modelId}/dbt-exposures": { + "get": { + "description": "Returns the dbt exposures for a model, computed on-demand by analyzing which dbt models are referenced by dashboards that use this model. Returns exactly one record per dashboard. The exposure field is null when a dashboard does not reference any dbt models. Exposure names (exposure.name) may contain duplicates when multiple dashboards produce the same name; use deduplication_name for a guaranteed-unique value, or use it as a fallback when names collide.", + "operationId": "modelsDbtExposures", + "summary": "Get dbt exposures", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Field to sort results by" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID to use for branch-aware operations", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": false, + "description": "Branch ID to use for branch-aware operations", + "name": "branch_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of dbt exposures for the model", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsDbtExposuresResponse" + } + } + } + }, + "400": { + "description": "Invalid request parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/branch/{branchName}/dbt": { + "post": { + "description": "Set the active dbt environment on a branch.", + "operationId": "modelsBranchDbt", + "summary": "Set branch dbt environment", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Branch name", + "example": "feature/new-metrics" + }, + "required": true, + "description": "Branch name", + "name": "branchName", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsBranchDbtBody" + } + } + } + }, + "responses": { + "200": { + "description": "dbt environment set successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or branch not found" + } + } + } + }, + "/api/v1/models/{modelId}/dbt-sync": { + "post": { + "description": "Trigger a dbt metadata sync (\"dbt quick sync\") for a branch. Recompiles the branch's dbt manifest and merges the regenerated dbt extension model, without a full database schema scan. The branch (via branch_id) supplies the dbt environment and dbt git branch. Runs as a background job.", + "operationId": "modelsDbtSync", + "summary": "Trigger a dbt metadata sync for a branch", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "ID of the branch to sync dbt metadata for. The branch supplies the dbt environment and dbt git branch to compile against (set via POST /api/v1/models/{modelId}/branch/{branchName}/dbt).", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "required": true, + "description": "ID of the branch to sync dbt metadata for. The branch supplies the dbt environment and dbt git branch to compile against (set via POST /api/v1/models/{modelId}/branch/{branchName}/dbt).", + "name": "branch_id", + "in": "query" + } + ], + "responses": { + "200": { + "description": "dbt sync job started", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JobCreatedResponse" + } + } + } + }, + "400": { + "description": "Invalid request parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or branch not found, or model deleted" + }, + "405": { + "description": "Method not allowed" + }, + "422": { + "description": "The model is not a shared model" + } + } + } + }, + "/api/v1/models/{modelId}/branch/{branchName}/merge": { + "post": { + "operationId": "modelsMergeBranch", + "summary": "Merge branch", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Branch name", + "example": "feature/new-metrics" + }, + "required": true, + "description": "Branch name", + "name": "branchName", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsMergeBranchBody" + } + } + } + }, + "responses": { + "200": { + "description": "Branch merged successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsMergeBranchResponse" + } + } + } + }, + "400": { + "description": "Invalid request body, merge not allowed, or merge conflict" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or PR required" + }, + "404": { + "description": "Model or branch not found" + } + } + } + }, + "/api/v1/models/{modelId}/git/commit": { + "post": { + "description": "Push the branch contents to git and create or update a pull request. The backend automatically detects whether the git branch already exists: if not, it creates a new git branch and opens a PR; if it does, it commits the latest model contents to the existing branch (updating the open PR).", + "operationId": "modelsCommit", + "summary": "Commit branch to git", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsCommitBody" + } + } + } + }, + "responses": { + "200": { + "description": "Branch committed to git and pull request created or updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsCommitResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or git not configured" + }, + "404": { + "description": "Model or branch not found" + } + } + } + }, + "/api/v1/models/{modelId}/cache_reset/{policyName}": { + "post": { + "operationId": "modelsCacheReset", + "summary": "Reset cache for policy", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cache policy name", + "example": "daily_refresh" + }, + "required": true, + "description": "Cache policy name", + "name": "policyName", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsCacheResetBody" + } + } + } + }, + "responses": { + "200": { + "description": "Cache reset scheduled", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsCacheResetResponse" + } + } + } + }, + "400": { + "description": "Invalid reset timestamp" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or cache policy not found" + } + } + } + }, + "/api/v1/models/{modelId}/git": { + "get": { + "operationId": "modelsGitGet", + "summary": "Get git configuration", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of optional fields to include. Supported: \"webhookSecret\"", + "example": "webhookSecret" + }, + "required": false, + "description": "Comma-separated list of optional fields to include. Supported: \"webhookSecret\"", + "name": "include", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Git configuration for the model", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found or git not configured" + } + } + }, + "post": { + "operationId": "modelsGitCreate", + "summary": "Create git configuration", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Git configuration created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid SSH URL or configuration" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + }, + "409": { + "description": "Git already configured for this model" + } + } + }, + "patch": { + "operationId": "modelsGitUpdate", + "summary": "Update git configuration", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Git configuration updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitUpdateResponse" + } + } + } + }, + "400": { + "description": "Invalid SSH URL or configuration" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found or git not configured" + } + } + }, + "delete": { + "operationId": "modelsGitDelete", + "summary": "Delete git configuration", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Git configuration deleted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found or git not configured" + } + } + } + }, + "/api/v1/models/{modelId}/git/sync": { + "post": { + "operationId": "modelsGitSync", + "summary": "Sync model with git", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitSyncBody" + } + } + } + }, + "responses": { + "200": { + "description": "Sync status and result (includes inSync=false for conflicts requiring manual resolution)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsGitSyncResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or git not configured" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/content-validator": { + "get": { + "operationId": "modelsContentValidatorGet", + "summary": "Validate content references", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID to validate against. Non-UUID values return 400." + }, + "required": false, + "description": "Optional branch ID to validate against. Non-UUID values return 400.", + "name": "branch_id", + "in": "query" + }, + { + "schema": { + "$ref": "#/components/schemas/ContentFilterMode" + }, + "required": false, + "description": "Filter documents by issue status. ALL (default) returns all documents with at least one query. WITH_ISSUES returns only documents with at least one query issue, dashboard filter issue, or document error. NO_ISSUES returns only documents with zero issues and no document errors.", + "name": "content_filter_mode", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter to documents created by this user (user ID). Unknown IDs return 400." + }, + "required": false, + "description": "Filter to documents created by this user (user ID). Unknown IDs return 400.", + "name": "creator_id", + "in": "query" + }, + { + "schema": { + "type": "string", + "minLength": 1, + "description": "Optional value to find. Used with find_type to scope validation to a single view, field, or topic. Requires find_type to be provided." + }, + "required": false, + "description": "Optional value to find. Used with find_type to scope validation to a single view, field, or topic. Requires find_type to be provided.", + "name": "find", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "FIELD", + "TOPIC", + "VIEW" + ], + "description": "Optional type of find operation (VIEW, FIELD, TOPIC). Requires find to be provided. FIELD values must be scoped by view name (e.g. view_name.field_name)." + }, + "required": false, + "description": "Optional type of find operation (VIEW, FIELD, TOPIC). Requires find to be provided. FIELD values must be scoped by view name (e.g. view_name.field_name).", + "name": "find_type", + "in": "query" + }, + { + "schema": { + "type": "array", + "description": "Prefix-match folder paths. \"/Finance\" matches \"/Finance/Reports\". Documents with no folder are excluded unless \"\" is specified.", + "items": { + "type": "string" + } + }, + "required": false, + "description": "Prefix-match folder paths. \"/Finance\" matches \"/Finance/Reports\". Documents with no folder are excluded unless \"\" is specified.", + "name": "folder_paths", + "in": "query" + }, + { + "schema": { + "type": "boolean", + "description": "Whether to include personal folders in validation" + }, + "required": false, + "description": "Whether to include personal folders in validation", + "name": "include_personal_folders", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated label names. Documents matching any label are included. Unknown labels return 400." + }, + "required": false, + "description": "Comma-separated label names. Documents matching any label are included. Unknown labels return 400.", + "name": "labels", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Optional user ID for scoping" + }, + "required": false, + "description": "Optional user ID for scoping", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Content validation results", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsContentValidatorGetResponse" + } + } + } + }, + "400": { + "description": "Invalid parameters or unknown labels" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + }, + "post": { + "operationId": "modelsContentValidatorReplace", + "summary": "Replace content references", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsContentValidatorReplaceBody" + } + } + } + }, + "responses": { + "200": { + "description": "Replace operation completed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsContentValidatorReplaceResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + } + }, + "/api/v1/models/{modelId}/yaml": { + "get": { + "operationId": "modelsYamlGet", + "summary": "Get model YAML", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID for branch-aware operations" + }, + "required": false, + "description": "Branch ID for branch-aware operations", + "name": "branchId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "File name to operate on" + }, + "required": false, + "description": "File name to operate on", + "name": "fileName", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "combined", + "extension", + "staged", + "merged", + "fully-resolved" + ], + "default": "combined", + "description": "IDE mode for YAML operations" + }, + "required": false, + "description": "IDE mode for YAML operations", + "name": "mode", + "in": "query" + }, + { + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ], + "default": false, + "description": "Resolve the model extends chain so the returned YAML reflects what runs at query time. Only valid with mode=combined." + }, + "required": false, + "description": "Resolve the model extends chain so the returned YAML reflects what runs at query time. Only valid with mode=combined.", + "name": "fullyResolved", + "in": "query" + }, + { + "schema": { + "type": [ + "boolean", + "null" + ], + "default": false, + "description": "Include checksums in response" + }, + "required": false, + "description": "Include checksums in response", + "name": "includeChecksums", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "A single schema name (optionally catalog-scoped, e.g. 'warehouse.reporting') to additionally load into the response. Use this to include view YAML from a schema that isn't active in the model (inactive or offloaded). Only views from this schema will be returned (views with no schema are always included)." + }, + "required": false, + "description": "A single schema name (optionally catalog-scoped, e.g. 'warehouse.reporting') to additionally load into the response. Use this to include view YAML from a schema that isn't active in the model (inactive or offloaded). Only views from this schema will be returned (views with no schema are always included).", + "name": "includeSchemas", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Model YAML content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelYamlResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + } + } + }, + "post": { + "operationId": "modelsYamlCreate", + "summary": "Update model YAML", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelYamlCreateRequestBody" + } + } + } + }, + "responses": { + "200": { + "description": "Model YAML updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelYamlResponse" + } + } + } + }, + "400": { + "description": "Invalid YAML or file name" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found" + }, + "409": { + "description": "Checksum mismatch (concurrent modification)" + } + } + }, + "delete": { + "operationId": "modelsYamlDelete", + "summary": "Delete model YAML file", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Branch ID for branch-aware operations" + }, + "required": false, + "description": "Branch ID for branch-aware operations", + "name": "branchId", + "in": "query" + }, + { + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "string" + } + ], + "description": "File name to delete (must end with '.topic' or '.view')" + }, + "required": true, + "description": "File name to delete (must end with '.topic' or '.view')", + "name": "fileName", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "combined", + "extension", + "staged", + "merged", + "fully-resolved" + ], + "default": "combined", + "description": "IDE mode for YAML operations" + }, + "required": false, + "description": "IDE mode for YAML operations", + "name": "mode", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Commit message for git sync" + }, + "required": false, + "description": "Commit message for git sync", + "name": "commitMessage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "YAML file deleted" + }, + "400": { + "description": "Invalid file name" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or file not found" + } + } + } + }, + "/api/v1/models/{modelId}/ai-agent-actions": { + "get": { + "description": "Returns the AI agent actions configured for this model \u2014 a unified list of sample queries and skills suitable for surfacing as suggested prompts above an AI prompt input. Sample queries come from both `model.sample_queries` and each topic's `sample_queries`; skills come from `model.skills` and each topic's `skills`, deduped by id with topic skills overriding model skills. Each entry's `prompt` is ready to submit verbatim to `POST /api/v1/ai/jobs`.", + "operationId": "modelAiAgentActions", + "summary": "Get model AI agent actions", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "AI agent actions in display order.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiAgentActionsResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key." + }, + "403": { + "description": "Caller cannot read the model." + }, + "404": { + "description": "Model not found." + } + } + } + }, + "/api/v1/query/run": { + "post": { + "operationId": "queryRun", + "summary": "Execute a semantic query", + "tags": [ + "Query" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryRunBody" + } + } + } + }, + "responses": { + "200": { + "description": "Query executed or started successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryRunResponse" + } + } + } + }, + "400": { + "description": "Invalid query definition or conflicting parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - querier role required on the model" + }, + "404": { + "description": "Model, topic, view, or branch not found" + }, + "408": { + "description": "Query timed out. The response includes remaining_job_ids that can be polled via the query/wait endpoint.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryTimeoutResponse" + } + } + } + }, + "500": { + "description": "Query execution error" + } + } + } + }, + "/api/v1/query/wait": { + "get": { + "operationId": "queryWait", + "summary": "Wait for query jobs to complete", + "tags": [ + "Query" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Comma-separated list of job IDs to wait for. Obtained from the query/run response.", + "example": "job_abc123,job_def456" + }, + "required": true, + "description": "Comma-separated list of job IDs to wait for. Obtained from the query/run response.", + "name": "jobIds", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Query results for completed jobs", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryWaitResponse" + } + } + } + }, + "400": { + "description": "Invalid or missing jobIds parameter" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Job ID not found" + }, + "500": { + "description": "Error fetching query results" + } + } + } + }, + "/api/v1/schedules": { + "get": { + "operationId": "schedulesList", + "summary": "List schedules", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "minLength": 1, + "default": 1, + "description": "The page number for offset-based pagination.", + "example": 1 + }, + "required": false, + "description": "The page number for offset-based pagination.", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "The direction to sort results (asc or desc).", + "example": "desc" + }, + "required": false, + "description": "The direction to sort results (asc or desc).", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "scheduleName", + "dashboardName", + "ownerName", + "lastRun", + "lastRunStatus" + ], + "default": "scheduleName", + "description": "The field to sort results by. Valid values: scheduleName, dashboardName, ownerName, lastRun, lastRunStatus.", + "example": "scheduleName" + }, + "required": false, + "description": "The field to sort results by. Valid values: scheduleName, dashboardName, ownerName, lastRun, lastRunStatus.", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "dashboard", + "single tile" + ], + "description": "Filter schedules by content type: dashboard, single tile.", + "example": "dashboard" + }, + "required": false, + "description": "Filter schedules by content type: dashboard, single tile.", + "name": "contentType", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter schedules by embed entity." + }, + "required": false, + "description": "Filter schedules by embed entity.", + "name": "embedEntity", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "email", + "google_sheets", + "s3", + "sftp", + "slack", + "webhook" + ], + "description": "Filter schedules by destination type: email, slack, webhook, sftp, s3.", + "example": "email" + }, + "required": false, + "description": "Filter schedules by destination type: email, slack, webhook, sftp, s3.", + "name": "destination", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter schedules by the document's unique identifier. Can be found in the dashboard's URL after /dashboards/.", + "example": "12db1a0a" + }, + "required": false, + "description": "Filter schedules by the document's unique identifier. Can be found in the dashboard's URL after /dashboards/.", + "name": "identifier", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter schedules by the owner's user ID. Use the List users endpoint to retrieve user IDs.", + "example": "987fcdeb-51a2-43d7-9b56-254415f67890" + }, + "required": false, + "description": "Filter schedules by the owner's user ID. Use the List users endpoint to retrieve user IDs.", + "name": "ownerId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Search term for filtering schedules by name, dashboard name, or owner name (case-insensitive).", + "example": "Weekly" + }, + "required": false, + "description": "Search term for filtering schedules by name, dashboard name, or owner name (case-insensitive).", + "name": "q", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "alert", + "schedule" + ], + "description": "Filter by type: alert, schedule.", + "example": "schedule" + }, + "required": false, + "description": "Filter by type: alert, schedule.", + "name": "scheduleType", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "success", + "error", + "canceled", + "none" + ], + "description": "Filter schedules by delivery status: success, error, canceled, none.", + "example": "success" + }, + "required": false, + "description": "Filter schedules by delivery status: success, error, canceled, none.", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of schedules", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SchedulesListItem" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + } + } + }, + "post": { + "description": "Create a new scheduled delivery for a dashboard. Required fields vary by destinationType (email, webhook, sftp, slack). For org API keys, use the userId query parameter to create the schedule on behalf of a specific user.", + "operationId": "schedulesCreate", + "summary": "Create schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Membership ID of the user who should own the schedule (org API keys only). If not provided, the schedule is owned by the API key owner. User-scoped API keys cannot use this parameter.", + "example": "987fcdeb-51a2-43d7-9b56-254415f67890" + }, + "required": false, + "description": "Membership ID of the user who should own the schedule (org API keys only). If not provided, the schedule is owned by the API key owner. User-scoped API keys cannot use this parameter.", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "bucketName": { + "type": "string", + "description": "S3 bucket name (S3 destination only). Must be 3-63 characters, lowercase.", + "example": "my-reports-bucket" + }, + "conditionQueryMapKey": { + "type": "string", + "description": "The ID of the query to monitor for triggering an alert. Required if conditionType is provided.", + "example": "Jmn2r3KV" + }, + "conditionType": { + "type": "string", + "enum": [ + "RESULTS_CHANGED", + "RESULTS_UNCHANGED", + "RESULTS_PRESENT", + "RESULTS_MISSING" + ], + "description": "Defines the type of condition to use for alerts. Required if conditionQueryMapKey is provided.", + "example": "RESULTS_PRESENT" + }, + "destinationType": { + "type": "string", + "enum": [ + "email", + "webhook", + "sftp", + "slack", + "s3" + ], + "description": "The delivery destination type", + "example": "email" + }, + "enableFormatting": { + "type": "boolean", + "description": "If true, formatting will be enabled in the output", + "example": false + }, + "fanOut": { + "type": "boolean", + "description": "If true, send personalized emails to each recipient (email only)", + "example": false + }, + "filterConfig": { + "description": "Filter conditions to apply to the task", + "example": { + "status": [ + "active", + "pending" + ] + } + }, + "format": { + "type": "string", + "enum": [ + "link_only", + "pdf", + "png", + "csv", + "xlsx", + "json" + ], + "description": "The output format: link_only, pdf, png, csv, xlsx, json", + "example": "pdf" + }, + "hideHiddenFields": { + "type": "boolean", + "description": "If true, hidden fields won't be displayed (csv/xlsx only)", + "example": false + }, + "hideTitle": { + "type": "boolean", + "description": "If true, hide the title in output (pdf/png only)", + "example": false + }, + "identifier": { + "type": "string", + "description": "The ID of the dashboard to schedule", + "example": "12db1a0a" + }, + "keyPrefix": { + "type": "string", + "description": "S3 key prefix / folder path (S3 destination only). Leading slashes are normalized.", + "example": "reports/weekly/" + }, + "killJobsOnFailure": { + "type": "boolean", + "description": "If true, stop entire job if any queries fail", + "example": false + }, + "name": { + "type": "string", + "description": "The name of the scheduled task", + "example": "Weekly Sales Report" + }, + "recipients": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Recipient email address", + "example": "user@example.com" + } + }, + "required": [ + "email" + ] + }, + "description": "Email recipients (email destination only). For Slack destinations, use the \"recipients\" field with a channel ID string or user ID(s) as a string or array." + }, + "region": { + "type": "string", + "description": "AWS region where the S3 bucket is located (S3 destination only).", + "example": "us-east-1" + }, + "roleArn": { + "type": "string", + "description": "ARN of the cross-account IAM role Omni will assume to write to the S3 bucket (S3 destination only).", + "example": "arn:aws:iam::123456789012:role/OmniS3DeliveryRole" + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", + "example": "0 9 ? * MON *" + }, + "showContentLink": { + "type": "boolean", + "description": "If true, include a link to the content", + "example": true + }, + "showFilters": { + "type": "boolean", + "description": "If true, show applied filters in output", + "example": true + }, + "slackRecipientType": { + "type": "string", + "description": "Slack recipient type (Slack destination only). Use \"channel\" to deliver to a single Slack channel, or \"users\" to deliver to one or more Slack users via direct message.", + "example": "channel" + }, + "testNow": { + "type": "boolean", + "description": "If true, run immediately instead of scheduling", + "example": false + }, + "timezone": { + "type": "string", + "description": "IANA timezone for the schedule", + "example": "America/New_York" + }, + "timezoneOverride": { + "type": [ + "string", + "null" + ], + "description": "Optional IANA timezone applied to query execution at render time. Distinct from `timezone` (which controls *when* the schedule fires). Omit or pass null for no override.", + "example": "Europe/Paris" + }, + "webhookUrl": { + "type": "string", + "format": "uri", + "description": "Webhook URL (webhook destination only)", + "example": "https://example.com/webhook" + } + }, + "required": [ + "destinationType", + "format", + "identifier", + "name", + "schedule", + "timezone" + ], + "description": "Request body for creating a scheduled task. Required fields vary by destinationType.", + "title": "SchedulesCreateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Schedule created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "delivererRoleArn": { + "type": "string", + "description": "The ARN of the Omni deliverer role. Use this as the Principal in your IAM role trust policy. Only returned for S3 destinations.", + "example": "arn:aws:iam::529831494235:role/OmniSchedulerDelivererRole" + }, + "externalId": { + "type": "string", + "format": "uuid", + "description": "The organization ID used as the external ID for confused deputy prevention. Add this to your IAM role trust policy as the sts:ExternalId condition. Static across all S3 destinations for your organization. Only returned for S3 destinations.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Created schedule ID (only when testNow is false)", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "message": { + "type": "string", + "description": "Success message", + "example": "Successfully created schedule" + } + }, + "required": [ + "message" + ], + "description": "Create schedule response", + "title": "SchedulesCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request body or filter configuration" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - cannot schedule this dashboard" + }, + "404": { + "description": "Dashboard not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}": { + "get": { + "operationId": "schedulesGet", + "summary": "Get schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Membership ID of the user whose access should be checked (org API keys only). When provided, the endpoint checks if that user has permission to view the schedule. User-scoped API keys cannot use this parameter.", + "example": "987fcdeb-51a2-43d7-9b56-254415f67890" + }, + "required": false, + "description": "Membership ID of the user whose access should be checked (org API keys only). When provided, the endpoint checks if that user has permission to view the schedule. User-scoped API keys cannot use this parameter.", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Schedule details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - must be schedule owner or have manage permission" + }, + "404": { + "description": "Schedule not found" + } + } + }, + "put": { + "operationId": "schedulesUpdate", + "summary": "Update schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schedule updated successfully" + }, + "400": { + "description": "Invalid request body or filter configuration" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - must be schedule owner or have manage permission" + }, + "404": { + "description": "Schedule or dashboard not found" + } + } + }, + "delete": { + "operationId": "schedulesDelete", + "summary": "Delete schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schedule deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - must be schedule owner or have manage permission" + }, + "404": { + "description": "Schedule not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/recipients": { + "get": { + "operationId": "schedulesRecipientsGet", + "summary": "Get schedule recipients", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schedule recipients", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesRecipientsGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Schedule not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/add-recipients": { + "put": { + "operationId": "schedulesAddRecipients", + "summary": "Add schedule recipients", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesAddRecipientsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Recipients added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesAddRecipientsResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - at least one email, userId, or userGroupId required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Schedule not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/remove-recipients": { + "put": { + "operationId": "schedulesRemoveRecipients", + "summary": "Remove schedule recipients", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesRemoveRecipientsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Recipients removed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesRemoveRecipientsResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - at least one email, userId, or userGroupId required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Schedule not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/pause": { + "put": { + "operationId": "schedulesPause", + "summary": "Pause schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schedule paused successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Schedule not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/resume": { + "put": { + "operationId": "schedulesResume", + "summary": "Resume schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schedule resumed successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Schedule not found" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/trigger": { + "post": { + "operationId": "schedulesTrigger", + "summary": "Trigger schedule", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schedule triggered successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Schedule not found" + }, + "409": { + "description": "Schedule cannot be triggered (paused, system-disabled, or another execution is in progress)" + } + } + } + }, + "/api/v1/schedules/{scheduleId}/transfer-ownership": { + "put": { + "operationId": "schedulesTransferOwnership", + "summary": "Transfer schedule ownership", + "tags": [ + "Schedules" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", + "name": "scheduleId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchedulesTransferOwnershipBody" + } + } + } + }, + "responses": { + "200": { + "description": "Ownership transferred successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid user ID" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - must be schedule owner or have manage permission" + }, + "404": { + "description": "Schedule or user not found" + } + } + } + }, + "/api/scim/v2/Users": { + "get": { + "operationId": "scimUsersList", + "summary": "List SCIM users", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "pattern": "^-?\\d*\\.?\\d+$", + "default": 100, + "description": "Maximum number of results to return", + "example": 100 + }, + "required": false, + "description": "Maximum number of results to return", + "name": "count", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "SCIM filter expression", + "example": "userName eq \"user@example.com\"" + }, + "required": false, + "description": "SCIM filter expression", + "name": "filter", + "in": "query" + }, + { + "schema": { + "type": "string", + "pattern": "^-?\\d*\\.?\\d+$", + "default": 1, + "description": "Index of the first result to return (1-based)", + "example": 1 + }, + "required": false, + "description": "Index of the first result to return (1-based)", + "name": "startIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of SCIM users", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUsersListResponse" + } + } + } + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + } + } + }, + "post": { + "operationId": "scimUsersCreate", + "summary": "Create SCIM user", + "tags": [ + "SCIM" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "SCIM user created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "409": { + "description": "User with this email already exists" + } + } + } + }, + "/api/scim/v2/Users/{id}": { + "get": { + "operationId": "scimUsersGet", + "summary": "Get SCIM user", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "SCIM user ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "SCIM user details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserResponse" + } + } + } + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "User not found" + } + } + }, + "put": { + "operationId": "scimUsersReplace", + "summary": "Replace SCIM user", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "SCIM user ID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserPutRequest" + } + } + } + }, + "responses": { + "200": { + "description": "SCIM user replaced", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "User not found" + } + } + }, + "patch": { + "operationId": "scimUsersUpdate", + "summary": "Update SCIM user", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "SCIM user ID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserPatchRequest" + } + } + } + }, + "responses": { + "200": { + "description": "SCIM user updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserResponse" + } + } + } + }, + "400": { + "description": "Invalid patch operations" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "User not found" + } + } + }, + "delete": { + "operationId": "scimUsersDelete", + "summary": "Delete SCIM user", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "SCIM user ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "204": { + "description": "SCIM user deleted" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "User not found" + } + } + } + }, + "/api/scim/v2/embed/Users": { + "get": { + "description": "List embed users. Embed users are externally-managed users created via the embed SSO flow.", + "operationId": "scimEmbedUsersList", + "summary": "List embed users", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "pattern": "^-?\\d*\\.?\\d+$", + "default": 100, + "description": "Maximum number of results to return", + "example": 100 + }, + "required": false, + "description": "Maximum number of results to return", + "name": "count", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "SCIM filter expression", + "example": "userName eq \"user@example.com\"" + }, + "required": false, + "description": "SCIM filter expression", + "name": "filter", + "in": "query" + }, + { + "schema": { + "type": "string", + "pattern": "^-?\\d*\\.?\\d+$", + "default": 1, + "description": "Index of the first result to return (1-based)", + "example": 1 + }, + "required": false, + "description": "Index of the first result to return (1-based)", + "name": "startIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of embed users", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUsersListResponse" + } + } + } + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + } + } + } + }, + "/api/scim/v2/embed/Users/{id}": { + "get": { + "description": "Get details for a specific embed user.", + "operationId": "scimEmbedUsersGet", + "summary": "Get embed user", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "SCIM user ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Embed user details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimUserResponse" + } + } + } + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "Embed user not found" + } + } + }, + "delete": { + "description": "Permanently delete an embed user. Unlike standard SCIM user deletion which soft-deletes, this performs a hard delete.", + "operationId": "scimEmbedUsersDelete", + "summary": "Delete embed user", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "SCIM user ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "SCIM user ID", + "name": "id", + "in": "path" + } + ], + "responses": { + "204": { + "description": "Embed user permanently deleted" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "Embed user not found" + } + } + } + }, + "/api/scim/v2/Groups": { + "get": { + "operationId": "scimGroupsList", + "summary": "List SCIM groups", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "pattern": "^-?\\d*\\.?\\d+$", + "default": 100, + "description": "Maximum number of results to return", + "example": 100 + }, + "required": false, + "description": "Maximum number of results to return", + "name": "count", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "members" + ], + "description": "Attributes to exclude from the response", + "example": "members" + }, + "required": false, + "description": "Attributes to exclude from the response", + "name": "excludedAttributes", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "SCIM filter expression", + "example": "displayName eq \"Engineering\"" + }, + "required": false, + "description": "SCIM filter expression", + "name": "filter", + "in": "query" + }, + { + "schema": { + "type": "string", + "pattern": "^-?\\d*\\.?\\d+$", + "default": 1, + "description": "Index of the first result to return (1-based)", + "example": 1 + }, + "required": false, + "description": "Index of the first result to return (1-based)", + "name": "startIndex", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of SCIM groups", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + } + } + }, + "post": { + "operationId": "scimGroupsCreate", + "summary": "Create SCIM group", + "tags": [ + "SCIM" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "SCIM group created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "409": { + "description": "Group with this name already exists" + } + } + } + }, + "/api/scim/v2/Groups/{miniUuid}": { + "get": { + "operationId": "scimGroupsGet", + "summary": "Get SCIM group", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "required": true, + "description": "Short identifier of the group", + "name": "miniUuid", + "in": "path" + }, + { + "schema": { + "type": "string", + "enum": [ + "members" + ], + "description": "Attributes to exclude from the response", + "example": "members" + }, + "required": false, + "description": "Attributes to exclude from the response", + "name": "excludedAttributes", + "in": "query" + } + ], + "responses": { + "200": { + "description": "SCIM group details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupResponse" + } + } + } + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "Group not found" + } + } + }, + "put": { + "operationId": "scimGroupsReplace", + "summary": "Replace SCIM group", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "required": true, + "description": "Short identifier of the group", + "name": "miniUuid", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupsReplaceBody" + } + } + } + }, + "responses": { + "200": { + "description": "SCIM group replaced", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "Group not found" + } + } + }, + "patch": { + "operationId": "scimGroupsUpdate", + "summary": "Update SCIM group", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "required": true, + "description": "Short identifier of the group", + "name": "miniUuid", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupsPatchBody" + } + } + } + }, + "responses": { + "200": { + "description": "SCIM group updated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ScimGroupResponse" + } + } + } + }, + "400": { + "description": "Invalid patch operations" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "Group not found" + } + } + }, + "delete": { + "operationId": "scimGroupsDelete", + "summary": "Delete SCIM group", + "tags": [ + "SCIM" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "required": true, + "description": "Short identifier of the group", + "name": "miniUuid", + "in": "path" + } + ], + "responses": { + "204": { + "description": "SCIM group deleted" + }, + "401": { + "description": "Authentication required (SCIM bearer token)" + }, + "404": { + "description": "Group not found" + } + } + } + }, + "/api/unstable/documents/{identifier}/export": { + "get": { + "operationId": "unstableDocumentsExport", + "summary": "Export document (unstable)", + "tags": [ + "Unstable" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (miniUuid or full UUID)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (miniUuid or full UUID)", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Document export data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentExportResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/unstable/documents/import": { + "post": { + "operationId": "unstableDocumentsImport", + "summary": "Import document (unstable)", + "tags": [ + "Unstable" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentImportBody" + } + } + } + }, + "responses": { + "201": { + "description": "Document imported successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentImportResponse" + } + } + } + }, + "400": { + "description": "Invalid export data" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Base model not found" + } + } + } + }, + "/api/v1/user-attributes": { + "get": { + "description": "Returns all user attribute definitions in the organization, including system-defined attributes (e.g. omni_user_id, omni_user_email) and custom attributes.", + "operationId": "userAttributesList", + "summary": "List all user attribute definitions", + "tags": [ + "User Attributes" + ], + "responses": { + "200": { + "description": "List of all user attribute definitions in the organization", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserAttributesListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" + } + } + } + }, + "/api/v1/uploads": { + "get": { + "operationId": "uploadsList", + "summary": "List uploads", + "tags": [ + "Uploads" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction (default: desc)", + "example": "desc" + }, + "required": false, + "description": "Sort direction (default: desc)", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "createdAt", + "fileName", + "updatedAt" + ], + "default": "updatedAt", + "description": "Field to sort by (default: updatedAt)" + }, + "required": false, + "description": "Field to sort by (default: updatedAt)", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by connection ID" + }, + "required": false, + "description": "Filter by connection ID", + "name": "connectionId", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by model ID. Shared models return connection uploads; workbook models return their own uploads." + }, + "required": false, + "description": "Filter by model ID. Shared models return connection uploads; workbook models return their own uploads.", + "name": "modelId", + "in": "query" + }, + { + "schema": { + "type": "string", + "maxLength": 256, + "description": "Search term to filter by file name" + }, + "required": false, + "description": "Search term to filter by file name", + "name": "searchTerm", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "csv", + "spreadsheet" + ], + "default": "csv", + "description": "Filter by upload type (default: csv)" + }, + "required": false, + "description": "Filter by upload type (default: csv)", + "name": "type", + "in": "query" + } + ], + "responses": { + "200": { + "description": "List of uploads with metadata", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadsListResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model not found (when modelId is provided)" + } + } + }, + "post": { + "operationId": "uploadsCreate", + "summary": "Upload CSV file", + "tags": [ + "Uploads" + ], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/UploadCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "CSV uploaded successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid request (missing fields, invalid file type, or CSV parsing failed)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Model or branch not found" + } + } + } + }, + "/api/v1/uploads/{uploadId}": { + "delete": { + "operationId": "uploadsDelete", + "summary": "Delete an upload", + "tags": [ + "Uploads" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "ID of the upload to delete" + }, + "required": true, + "description": "ID of the upload to delete", + "name": "uploadId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Upload deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadDeleteResponse" + } + } + } + }, + "400": { + "description": "Invalid upload ID format" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" + }, + "404": { + "description": "Upload not found or already deleted" + } + } + } + }, + "/api/v1/users/{id}/model-roles": { + "get": { + "operationId": "usersGetModelRoles", + "summary": "Get user model roles", + "tags": [ + "Users" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "User membership ID", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter results to a specific connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": false, + "description": "Filter results to a specific connection", + "name": "connectionId", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter results to a specific model", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": false, + "description": "Filter results to a specific model", + "name": "modelId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "User model role assignments", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersGetModelRolesResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "User not found" + } + } + }, + "post": { + "operationId": "usersAssignModelRole", + "summary": "Assign model role to user", + "tags": [ + "Users" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "User membership ID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersAssignModelRoleBody" + } + } + } + }, + "responses": { + "200": { + "description": "Role assigned successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersAssignModelRoleResponse" + } + } + } + }, + "400": { + "description": "Invalid request - connectionId or modelId required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "User, model, or connection not found" + } + } + } + }, + "/api/v1/users/email-only": { + "get": { + "operationId": "usersListEmailOnly", + "summary": "List email-only users", + "tags": [ + "Users" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination" + }, + "required": false, + "description": "Cursor for pagination", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by email address", + "example": "user@example.com" + }, + "required": false, + "description": "Filter by email address", + "name": "email", + "in": "query" + }, + { + "schema": { + "type": "number", + "minimum": 1, + "maximum": 20, + "default": 20, + "description": "Number of results per page (max 20)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (max 20)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of email-only users", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersListEmailOnlyResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + }, + "post": { + "operationId": "usersCreateEmailOnly", + "summary": "Create or update email-only user", + "tags": [ + "Users" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersCreateEmailOnlyBody" + } + } + } + }, + "responses": { + "200": { + "description": "Email-only user created or updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersCreateEmailOnlyResponse" + } + } + } + }, + "400": { + "description": "Invalid email address or failed to create user" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + } + }, + "/api/v1/users/email-only/bulk": { + "post": { + "operationId": "usersCreateEmailOnlyBulk", + "summary": "Create email-only users in bulk", + "tags": [ + "Users" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersCreateEmailOnlyBulkBody" + } + } + } + }, + "responses": { + "201": { + "description": "Email-only users created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersCreateEmailOnlyBulkResponse" + } + } + } + }, + "400": { + "description": "Invalid request - must provide 1-20 users with valid emails" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + } + }, + "/api/v1/user-groups/{id}/model-roles": { + "get": { + "operationId": "userGroupsGetModelRoles", + "summary": "Get user group model roles", + "tags": [ + "Users" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "User group short identifier (miniUuid)", + "example": "abc123" + }, + "required": true, + "description": "User group short identifier (miniUuid)", + "name": "id", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter results to a specific connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": false, + "description": "Filter results to a specific connection", + "name": "connectionId", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter results to a specific model", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": false, + "description": "Filter results to a specific model", + "name": "modelId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "User group model role assignments", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserGroupsGetModelRolesResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "User group not found" + } + } + }, + "post": { + "operationId": "userGroupsAssignModelRole", + "summary": "Assign model role to user group", + "tags": [ + "Users" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "User group short identifier (miniUuid)", + "example": "abc123" + }, + "required": true, + "description": "User group short identifier (miniUuid)", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserGroupsAssignModelRoleBody" + } + } + } + }, + "responses": { + "200": { + "description": "Role assigned successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserGroupsAssignModelRoleResponse" + } + } + } + }, + "400": { + "description": "Invalid request - connectionId or modelId required" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + }, + "404": { + "description": "User group, model, or connection not found" + } + } + } + }, + "/api/v1/whoami": { + "get": { + "description": "Returns the authenticated caller's own identity, API key scope, organization role, and resolved per-model permissions. Self-scoped and available to non-admins: it lets a caller decide whether an action is permitted without attempting it. Pass `modelId` to scope `rolesByModel` to specific models.", + "operationId": "whoami", + "summary": "Get current identity and permissions (whoami)", + "tags": [ + "Whoami" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Optional model filter. A single model id or a comma-separated list. When provided, `rolesByModel` contains only these models. When omitted, models the caller can access are returned (up to a limit; see `rolesByModelTruncated`).", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": false, + "description": "Optional model filter. A single model id or a comma-separated list. When provided, `rolesByModel` contains only these models. When omitted, models the caller can access are returned (up to a limit; see `rolesByModelTruncated`).", + "name": "modelId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Caller's identity, key scope, org role, and per-model permissions", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WhoamiResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "One or more requested `modelId`s do not exist or are not accessible to the caller" + } + } + } + } + }, + "webhooks": {} +} \ No newline at end of file From 66f91dd246e723725b8fdb948d7bddae5cdb3646 Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Thu, 16 Jul 2026 12:34:28 -0700 Subject: [PATCH 02/11] Replace hand-written OmniAPI with generated client Generated by openapi-python-client 0.29.0 from spec/openapi.json via scripts/generate.sh: 195 operations across 22 tag modules, 597 typed models, sync + async. Removes the hand-written api.py (~30 endpoints). Co-Authored-By: Claude Fable 5 --- omni_python_sdk/__init__.py | 9 +- omni_python_sdk/api.py | 779 ---------- omni_python_sdk/api/__init__.py | 1 + omni_python_sdk/api/ai/__init__.py | 1 + omni_python_sdk/api/ai/ai_branding.py | 160 +++ .../api/ai/ai_conversation_detail.py | 186 +++ .../api/ai/ai_conversations_list.py | 238 ++++ .../api/ai/ai_credit_controls_get.py | 160 +++ .../api/ai/ai_credit_controls_update.py | 206 +++ .../api/ai/ai_credit_controls_users_list.py | 225 +++ .../api/ai/ai_credit_controls_users_update.py | 212 +++ omni_python_sdk/api/ai/ai_generate_query.py | 222 +++ omni_python_sdk/api/ai/ai_job_cancel.py | 214 +++ omni_python_sdk/api/ai/ai_job_result.py | 204 +++ omni_python_sdk/api/ai/ai_job_status.py | 204 +++ omni_python_sdk/api/ai/ai_job_submit.py | 238 ++++ .../api/ai/ai_job_visualization.py | 204 +++ omni_python_sdk/api/ai/ai_pick_topic.py | 204 +++ omni_python_sdk/api/ai/ai_search_omni_docs.py | 198 +++ omni_python_sdk/api/ai_eval/__init__.py | 1 + .../ai_eval/ai_eval_prompt_sets_archive.py | 263 ++++ .../api/ai_eval/ai_eval_prompt_sets_create.py | 196 +++ .../api/ai_eval/ai_eval_prompt_sets_get.py | 192 +++ .../api/ai_eval/ai_eval_prompt_sets_list.py | 242 ++++ .../ai_eval/ai_eval_prompt_sets_unarchive.py | 192 +++ .../api/ai_eval/ai_eval_prompt_sets_update.py | 272 ++++ .../api/ai_eval/ai_eval_runs_archive.py | 200 +++ .../api/ai_eval/ai_eval_runs_cancel.py | 200 +++ .../api/ai_eval/ai_eval_runs_create.py | 287 ++++ .../api/ai_eval/ai_eval_runs_get.py | 190 +++ .../api/ai_eval/ai_eval_runs_list.py | 226 +++ .../api/ai_eval/ai_eval_runs_unarchive.py | 186 +++ .../api/ai_model_suggestions/__init__.py | 1 + .../model_suggestions_delete.py | 204 +++ .../model_suggestions_ignore.py | 226 +++ .../model_suggestions_list.py | 263 ++++ .../model_suggestions_restore.py | 208 +++ .../model_suggestions_schedule_disable.py | 190 +++ .../model_suggestions_schedule_enable.py | 214 +++ omni_python_sdk/api/ai_routines/__init__.py | 1 + .../api/ai_routines/routine_create.py | 238 ++++ .../api/ai_routines/routine_delete.py | 212 +++ .../api/ai_routines/routine_get.py | 212 +++ .../api/ai_routines/routine_trigger.py | 230 +++ .../api/ai_routines/routine_update.py | 236 +++ .../api/ai_routines/routines_list.py | 285 ++++ omni_python_sdk/api/api_tokens/__init__.py | 1 + .../api/api_tokens/api_keys_delete.py | 184 +++ .../api/api_tokens/api_keys_get.py | 176 +++ .../api/api_tokens/api_keys_list.py | 275 ++++ .../api/api_tokens/api_keys_update.py | 197 +++ omni_python_sdk/api/connections/__init__.py | 1 + .../connection_environments_create.py | 185 +++ .../connection_environments_delete.py | 170 +++ .../connection_environments_update.py | 202 +++ .../api/connections/connections_create.py | 193 +++ .../api/connections/connections_dbt_delete.py | 170 +++ .../connections_dbt_environments_create.py | 201 +++ .../connections_dbt_environments_delete.py | 190 +++ .../connections_dbt_environments_list.py | 272 ++++ .../connections_dbt_environments_update.py | 215 +++ .../api/connections/connections_dbt_get.py | 187 +++ .../api/connections/connections_dbt_update.py | 196 +++ .../api/connections/connections_delete.py | 192 +++ .../api/connections/connections_get.py | 176 +++ .../api/connections/connections_list.py | 267 ++++ .../connections_schedules_create.py | 202 +++ .../connections_schedules_delete.py | 184 +++ .../connections/connections_schedules_get.py | 184 +++ .../connections/connections_schedules_list.py | 170 +++ .../connections_schedules_update.py | 216 +++ .../api/connections/connections_update.py | 230 +++ omni_python_sdk/api/content/__init__.py | 1 + omni_python_sdk/api/content/content_list.py | 326 +++++ omni_python_sdk/api/dashboards/__init__.py | 1 + .../api/dashboards/dashboards_download.py | 225 +++ .../dashboards/dashboards_download_file.py | 140 ++ .../dashboards/dashboards_download_status.py | 131 ++ .../api/dashboards/dashboards_get_filters.py | 192 +++ .../dashboards/dashboards_update_filters.py | 221 +++ omni_python_sdk/api/documents/__init__.py | 1 + .../api/documents/documents_access_list.py | 302 ++++ .../api/documents/documents_add_favorite.py | 128 ++ .../api/documents/documents_add_label.py | 134 ++ .../api/documents/documents_add_permits.py | 195 +++ .../documents/documents_bulk_update_labels.py | 221 +++ .../api/documents/documents_create.py | 177 +++ .../api/documents/documents_create_draft.py | 197 +++ .../api/documents/documents_delete.py | 169 +++ .../api/documents/documents_discard_draft.py | 193 +++ .../api/documents/documents_duplicate.py | 221 +++ .../api/documents/documents_get.py | 191 +++ .../documents/documents_get_permissions.py | 194 +++ .../api/documents/documents_get_queries.py | 171 +++ .../api/documents/documents_list.py | 320 +++++ .../api/documents/documents_list_drafts.py | 225 +++ .../api/documents/documents_list_favorites.py | 261 ++++ .../api/documents/documents_move.py | 195 +++ .../api/documents/documents_put.py | 237 ++++ .../documents/documents_remove_favorite.py | 128 ++ .../api/documents/documents_remove_label.py | 134 ++ .../api/documents/documents_revoke_permits.py | 195 +++ .../documents/documents_transfer_ownership.py | 195 +++ .../api/documents/documents_update.py | 237 ++++ .../documents_update_permission_settings.py | 195 +++ .../api/documents/documents_update_permits.py | 195 +++ .../api/documents/documents_upgrade_layout.py | 221 +++ .../api/documents/documents_v2_create.py | 240 ++++ .../api/documents/documents_v2_get.py | 253 ++++ .../api/documents/documents_v2_get_draft.py | 259 ++++ .../api/documents/documents_v2_patch_draft.py | 233 +++ .../documents_v2_patch_draft_by_identifier.py | 235 +++ .../documents/documents_v2_publish_draft.py | 211 +++ .../documents_v2_update_identifier.py | 236 +++ omni_python_sdk/api/embed/__init__.py | 1 + .../api/embed/embed_sso_generate_session.py | 173 +++ omni_python_sdk/api/folders/__init__.py | 1 + .../api/folders/folders_add_permissions.py | 198 +++ omni_python_sdk/api/folders/folders_create.py | 173 +++ omni_python_sdk/api/folders/folders_delete.py | 230 +++ .../api/folders/folders_get_permissions.py | 200 +++ omni_python_sdk/api/folders/folders_list.py | 350 +++++ .../api/folders/folders_revoke_permissions.py | 198 +++ omni_python_sdk/api/folders/folders_update.py | 218 +++ .../api/folders/folders_update_permissions.py | 198 +++ omni_python_sdk/api/labels/__init__.py | 1 + omni_python_sdk/api/labels/labels_create.py | 201 +++ omni_python_sdk/api/labels/labels_delete.py | 129 ++ omni_python_sdk/api/labels/labels_get.py | 163 +++ omni_python_sdk/api/labels/labels_list.py | 132 ++ omni_python_sdk/api/labels/labels_update.py | 221 +++ omni_python_sdk/api/models/__init__.py | 1 + omni_python_sdk/api/models/jobs_get_status.py | 187 +++ .../api/models/model_ai_agent_actions.py | 192 +++ .../api/models/models_branch_dbt.py | 213 +++ .../api/models/models_cache_reset.py | 208 +++ omni_python_sdk/api/models/models_commit.py | 209 +++ .../models/models_content_validator_get.py | 375 +++++ .../models_content_validator_replace.py | 217 +++ omni_python_sdk/api/models/models_create.py | 185 +++ .../api/models/models_create_field.py | 192 +++ .../api/models/models_dbt_exposures.py | 303 ++++ omni_python_sdk/api/models/models_dbt_sync.py | 230 +++ .../api/models/models_delete_branch.py | 180 +++ .../api/models/models_delete_field.py | 233 +++ .../api/models/models_delete_topic.py | 240 ++++ .../api/models/models_delete_view.py | 240 ++++ .../api/models/models_get_schemas.py | 196 +++ .../api/models/models_get_topic.py | 210 +++ .../api/models/models_get_views.py | 196 +++ .../api/models/models_git_create.py | 198 +++ .../api/models/models_git_delete.py | 168 +++ omni_python_sdk/api/models/models_git_get.py | 193 +++ omni_python_sdk/api/models/models_git_sync.py | 190 +++ .../api/models/models_git_update.py | 194 +++ omni_python_sdk/api/models/models_list.py | 352 +++++ .../api/models/models_list_topics.py | 196 +++ .../api/models/models_merge_branch.py | 208 +++ omni_python_sdk/api/models/models_migrate.py | 192 +++ omni_python_sdk/api/models/models_refresh.py | 282 ++++ omni_python_sdk/api/models/models_update.py | 201 +++ .../api/models/models_update_field.py | 247 ++++ .../api/models/models_update_topic.py | 233 +++ .../api/models/models_update_view.py | 233 +++ omni_python_sdk/api/models/models_validate.py | 207 +++ .../api/models/models_yaml_create.py | 198 +++ .../api/models/models_yaml_delete.py | 163 +++ omni_python_sdk/api/models/models_yaml_get.py | 298 ++++ omni_python_sdk/api/query/__init__.py | 1 + omni_python_sdk/api/query/query_run.py | 211 +++ omni_python_sdk/api/query/query_wait.py | 180 +++ omni_python_sdk/api/schedules/__init__.py | 1 + .../api/schedules/schedules_add_recipients.py | 198 +++ .../api/schedules/schedules_create.py | 229 +++ .../api/schedules/schedules_delete.py | 170 +++ .../api/schedules/schedules_get.py | 208 +++ .../api/schedules/schedules_list.py | 415 ++++++ .../api/schedules/schedules_pause.py | 170 +++ .../api/schedules/schedules_recipients_get.py | 172 +++ .../schedules/schedules_remove_recipients.py | 198 +++ .../api/schedules/schedules_resume.py | 170 +++ .../schedules/schedules_transfer_ownership.py | 196 +++ .../api/schedules/schedules_trigger.py | 174 +++ .../api/schedules/schedules_update.py | 113 ++ omni_python_sdk/api/scim/__init__.py | 1 + .../api/scim/scim_embed_users_delete.py | 111 ++ .../api/scim/scim_embed_users_get.py | 170 +++ .../api/scim/scim_embed_users_list.py | 206 +++ .../api/scim/scim_groups_create.py | 173 +++ .../api/scim/scim_groups_delete.py | 104 ++ omni_python_sdk/api/scim/scim_groups_get.py | 195 +++ omni_python_sdk/api/scim/scim_groups_list.py | 224 +++ .../api/scim/scim_groups_replace.py | 189 +++ .../api/scim/scim_groups_update.py | 189 +++ omni_python_sdk/api/scim/scim_users_create.py | 171 +++ omni_python_sdk/api/scim/scim_users_delete.py | 105 ++ omni_python_sdk/api/scim/scim_users_get.py | 162 +++ omni_python_sdk/api/scim/scim_users_list.py | 198 +++ .../api/scim/scim_users_replace.py | 188 +++ omni_python_sdk/api/scim/scim_users_update.py | 188 +++ omni_python_sdk/api/unstable/__init__.py | 1 + .../api/unstable/unstable_documents_export.py | 167 +++ .../api/unstable/unstable_documents_import.py | 177 +++ omni_python_sdk/api/uploads/__init__.py | 1 + omni_python_sdk/api/uploads/uploads_create.py | 176 +++ omni_python_sdk/api/uploads/uploads_delete.py | 172 +++ omni_python_sdk/api/uploads/uploads_list.py | 323 +++++ .../api/user_attributes/__init__.py | 1 + .../user_attributes/user_attributes_list.py | 148 ++ omni_python_sdk/api/users/__init__.py | 1 + .../users/user_groups_assign_model_role.py | 193 +++ .../api/users/user_groups_get_model_roles.py | 218 +++ .../api/users/users_assign_model_role.py | 194 +++ .../api/users/users_create_email_only.py | 173 +++ .../api/users/users_create_email_only_bulk.py | 173 +++ .../api/users/users_get_model_roles.py | 218 +++ .../api/users/users_list_email_only.py | 224 +++ omni_python_sdk/api/whoami/__init__.py | 1 + omni_python_sdk/api/whoami/whoami.py | 198 +++ omni_python_sdk/client.py | 268 ++++ omni_python_sdk/errors.py | 16 + omni_python_sdk/models/__init__.py | 1263 +++++++++++++++++ omni_python_sdk/models/ai_agent_action.py | 83 ++ .../models/ai_agent_action_kind.py | 14 + .../models/ai_agent_actions_response.py | 76 + .../models/ai_branding_response.py | 103 ++ omni_python_sdk/models/ai_conversation.py | 111 ++ .../models/ai_conversation_detail_response.py | 115 ++ .../models/ai_conversation_message.py | 126 ++ .../models/ai_conversation_message_role.py | 14 + .../models/ai_conversations_list_response.py | 85 ++ .../models/ai_credit_controls_response.py | 129 ++ .../models/ai_credit_controls_update_body.py | 99 ++ .../ai_credit_controls_users_list_response.py | 90 ++ ...ntrols_users_list_response_records_item.py | 77 + .../models/ai_credit_shutoff_error.py | 80 ++ .../models/ai_credit_shutoff_error_code.py | 13 + .../ai_eval_prompt_sets_list_archived.py | 14 + .../models/ai_eval_runs_list_archived.py | 14 + .../models/ai_generate_query_body.py | 149 ++ .../models/ai_generate_query_response.py | 184 +++ ...ai_generate_query_response_error_type_0.py | 72 + .../ai_generate_query_response_result.py | 50 + omni_python_sdk/models/ai_job_action.py | 103 ++ .../models/ai_job_action_query_result.py | 137 ++ .../ai_job_action_query_result_query.py | 50 + .../ai_job_action_query_result_status.py | 14 + .../models/ai_job_cancel_response.py | 74 + .../models/ai_job_cancel_response_state.py | 18 + .../models/ai_job_result_response.py | 126 ++ .../models/ai_job_status_response.py | 343 +++++ .../models/ai_job_status_response_error.py | 82 ++ .../ai_job_status_response_progress_type_0.py | 82 ++ .../models/ai_job_status_response_state.py | 18 + omni_python_sdk/models/ai_job_submit_body.py | 180 +++ .../ai_job_submit_body_webhook_metadata.py | 53 + .../models/ai_job_submit_response.py | 82 ++ omni_python_sdk/models/ai_pick_topic_body.py | 132 ++ .../models/ai_pick_topic_response.py | 62 + omni_python_sdk/models/ai_query_sort.py | 70 + .../models/ai_search_omni_docs_body.py | 62 + .../models/ai_search_omni_docs_response.py | 85 ++ ..._search_omni_docs_response_sources_item.py | 69 + omni_python_sdk/models/ai_semantic_query.py | 50 + omni_python_sdk/models/ai_topic_params.py | 92 ++ .../models/ai_user_credit_limit_entry.py | 75 + .../models/ai_user_credit_limits_response.py | 75 + ..._user_credit_limits_response_users_item.py | 84 ++ .../ai_user_credit_limits_update_body.py | 57 + omni_python_sdk/models/api_document.py | 289 ++++ omni_python_sdk/models/api_document_count.py | 70 + omni_python_sdk/models/api_draft.py | 167 +++ omni_python_sdk/models/api_draft_actor.py | 62 + .../models/api_draft_branch_type_0.py | 71 + omni_python_sdk/models/api_draft_status.py | 14 + omni_python_sdk/models/api_error_400.py | 69 + omni_python_sdk/models/api_error_401.py | 70 + omni_python_sdk/models/api_error_403.py | 70 + omni_python_sdk/models/api_error_404.py | 70 + omni_python_sdk/models/api_error_409.py | 70 + omni_python_sdk/models/api_error_422.py | 62 + omni_python_sdk/models/api_error_429.py | 70 + omni_python_sdk/models/api_key.py | 126 ++ .../models/api_key_delete_response.py | 69 + .../models/api_key_list_response.py | 85 ++ omni_python_sdk/models/api_key_type.py | 15 + omni_python_sdk/models/api_key_update_body.py | 42 + .../models/api_keys_list_sort_direction.py | 14 + .../models/api_keys_list_sort_field.py | 14 + omni_python_sdk/models/api_keys_list_type.py | 15 + omni_python_sdk/models/api_vis_config.py | 47 + omni_python_sdk/models/composite_filter.py | 257 ++++ .../models/composite_filter_conjunction.py | 14 + .../composite_filter_filters_item_type_0.py | 160 +++ ...lter_filters_item_type_0_applied_labels.py | 47 + ...mposite_filter_filters_item_type_0_kind.py | 18 + ...mposite_filter_filters_item_type_0_type.py | 13 + .../composite_filter_filters_item_type_1.py | 147 ++ ...mposite_filter_filters_item_type_1_kind.py | 16 + ...mposite_filter_filters_item_type_1_type.py | 13 + .../composite_filter_filters_item_type_2.py | 270 ++++ ...mposite_filter_filters_item_type_2_kind.py | 41 + ...mposite_filter_filters_item_type_2_type.py | 13 + ...lter_filters_item_type_2_ui_type_type_1.py | 47 + ...lters_item_type_2_ui_type_type_2_type_1.py | 51 + ...lters_item_type_2_ui_type_type_3_type_1.py | 51 + .../composite_filter_filters_item_type_3.py | 105 ++ ...mposite_filter_filters_item_type_3_type.py | 13 + .../composite_filter_filters_item_type_4.py | 114 ++ ...mposite_filter_filters_item_type_4_type.py | 13 + .../composite_filter_filters_item_type_5.py | 154 ++ ...mposite_filter_filters_item_type_5_type.py | 13 + ...e_filter_filters_item_type_5_view_query.py | 118 ++ ..._filters_item_type_5_view_query_filters.py | 47 + .../composite_filter_filters_item_type_6.py | 93 ++ ...mposite_filter_filters_item_type_6_type.py | 13 + .../models/composite_filter_type.py | 13 + ...te_connections_environments_create_body.py | 80 ++ ...onnections_environments_create_response.py | 88 ++ ..._create_response_connection_environment.py | 88 ++ ...onnections_environments_delete_response.py | 62 + ...te_connections_environments_update_body.py | 63 + ...onnections_environments_update_response.py | 62 + ...nections_create_connections_create_body.py | 476 +++++++ ...reate_connections_create_body_base_role.py | 24 + ..._create_connections_create_body_dialect.py | 51 + ...ions_create_connections_create_response.py | 71 + ..._delete_connections_dbt_delete_response.py | 70 + ...ns_dbt_environments_list_sort_direction.py | 16 + ...ctions_dbt_environments_list_sort_field.py | 15 + ...ections_dbt_get_dbt_configured_response.py | 124 ++ ...ons_dbt_get_dbt_not_configured_response.py | 70 + ..._dbt_update_connections_dbt_update_body.py | 165 +++ ...bt_update_body_project_root_path_type_1.py | 19 + ..._update_connections_dbt_update_response.py | 70 + ...ions_delete_connections_delete_response.py | 70 + ...onnections_get_connections_get_response.py | 72 + ...get_connections_get_response_connection.py | 253 ++++ ...ections_get_response_connection_dialect.py | 49 + ...nections_list_connections_list_response.py | 80 ++ ...st_connections_list_response_connection.py | 253 ++++ ...ctions_list_response_connection_dialect.py | 49 + .../models/connections_list_sort_direction.py | 14 + .../models/connections_list_sort_field.py | 15 + ...reate_connections_schedules_create_body.py | 84 ++ ...e_connections_schedules_create_response.py | 136 ++ ...e_connections_schedules_delete_response.py | 62 + ..._get_connections_schedules_get_response.py | 136 ++ ...ist_connections_schedules_list_response.py | 83 ++ ...dules_list_response_connection_schedule.py | 136 ++ ...pdate_connections_schedules_update_body.py | 84 ++ ...e_connections_schedules_update_response.py | 136 ++ ...nections_update_connections_update_body.py | 135 ++ ..._body_environment_user_attribute_type_0.py | 88 ++ ...ions_update_connections_update_response.py | 70 + omni_python_sdk/models/containers_item.py | 47 + omni_python_sdk/models/content_filter_mode.py | 15 + .../models/content_list_response.py | 112 ++ ...ntent_list_response_records_item_type_0.py | 301 ++++ ..._list_response_records_item_type_0_type.py | 15 + ...ntent_list_response_records_item_type_1.py | 154 ++ ...list_response_records_item_type_1_count.py | 70 + ...list_response_records_item_type_1_owner.py | 70 + ...list_response_records_item_type_1_scope.py | 16 + ..._list_response_records_item_type_1_type.py | 15 + omni_python_sdk/models/content_list_scope.py | 14 + .../models/content_list_sort_direction.py | 14 + .../models/content_list_sort_field.py | 14 + omni_python_sdk/models/content_share_scope.py | 14 + .../models/control_patch_external.py | 47 + .../models/control_read_external.py | 47 + .../models/controls_patch_external.py | 47 + .../models/controls_read_external.py | 47 + .../models/create_model_schema_base.py | 211 +++ ...te_model_schema_base_access_grants_item.py | 126 ++ ...a_base_access_grants_item_code_comments.py | 47 + ...ate_model_schema_base_model_kind_type_0.py | 15 + ...ate_model_schema_base_model_kind_type_1.py | 15 + ...ate_model_schema_base_model_kind_type_2.py | 15 + ...ate_model_schema_base_model_kind_type_3.py | 15 + .../models/dashboard_filters_response.py | 92 ++ .../models/dashboards_download_body.py | 219 +++ .../models/dashboards_download_body_format.py | 17 + .../dashboards_download_body_paper_format.py | 18 + ...hboards_download_body_paper_orientation.py | 16 + .../models/dashboards_download_response.py | 71 + .../models/dashboards_update_filters_body.py | 115 ++ ...dashboards_update_filters_body_controls.py | 66 + ...lters_body_controls_additional_property.py | 47 + .../dashboards_update_filters_body_filters.py | 66 + ...ilters_body_filters_additional_property.py | 47 + .../models/dbt_environment_create_body.py | 189 +++ .../models/dbt_environment_delete_response.py | 69 + .../models/dbt_environment_item.py | 173 +++ .../models/dbt_environment_list_response.py | 85 ++ .../dbt_environment_response_variable.py | 92 ++ .../models/dbt_environment_update_body.py | 219 +++ .../models/dbt_environment_variable.py | 77 + .../models/dbt_environment_variable_update.py | 75 + omni_python_sdk/models/dbt_exposure.py | 115 ++ omni_python_sdk/models/dbt_exposure_owner.py | 69 + omni_python_sdk/models/dbt_exposure_type.py | 17 + .../models/dbt_exposure_with_meta.py | 84 ++ omni_python_sdk/models/document.py | 249 ++++ omni_python_sdk/models/document_count.py | 70 + .../models/document_export_response.py | 123 ++ .../document_export_response_document.py | 72 + .../document_export_response_file_uploads.py | 47 + .../document_export_response_query_models.py | 47 + .../models/document_favorite_user.py | 94 ++ .../models/document_folder_type_0.py | 88 ++ .../models/document_folder_type_0_scope.py | 14 + .../models/document_import_body.py | 154 ++ .../models/document_import_body_document.py | 72 + .../document_import_body_export_version.py | 13 + .../document_import_body_file_uploads.py | 47 + .../document_import_body_query_models.py | 47 + .../models/document_import_response.py | 70 + omni_python_sdk/models/document_owner.py | 70 + omni_python_sdk/models/document_scope.py | 14 + omni_python_sdk/models/document_type.py | 13 + .../documents_access_list_access_source.py | 14 + .../models/documents_access_list_response.py | 75 + .../documents_access_list_sort_direction.py | 14 + .../models/documents_access_list_type.py | 14 + .../models/documents_add_permits_body.py | 106 ++ .../models/documents_add_permits_body_role.py | 17 + .../documents_bulk_update_labels_body.py | 74 + .../documents_bulk_update_labels_response.py | 61 + .../models/documents_create_body.py | 196 +++ ...ts_create_body_query_presentations_item.py | 185 +++ ...ate_body_query_presentations_item_query.py | 70 + .../models/documents_create_draft_body.py | 69 + .../models/documents_create_draft_response.py | 61 + .../models/documents_create_response.py | 77 + .../documents_create_response_dashboard.py | 70 + .../documents_create_response_workbook.py | 70 + .../models/documents_discard_draft_body.py | 69 + .../documents_discard_draft_response.py | 61 + .../models/documents_duplicate_body.py | 100 ++ .../models/documents_duplicate_body_scope.py | 14 + .../models/documents_duplicate_response.py | 85 ++ .../documents_get_permissions_response.py | 61 + .../models/documents_get_queries_response.py | 75 + ...ments_get_queries_response_queries_item.py | 96 ++ .../models/documents_get_response.py | 147 ++ .../documents_list_favorites_response.py | 85 ++ ...documents_list_favorites_sort_direction.py | 14 + .../models/documents_list_response.py | 85 ++ .../models/documents_list_sort_direction.py | 14 + .../models/documents_list_sort_field.py | 16 + omni_python_sdk/models/documents_move_body.py | 87 ++ .../models/documents_move_body_scope.py | 14 + omni_python_sdk/models/documents_put_body.py | 171 +++ .../documents_put_query_presentation.py | 264 ++++ ...uments_put_query_presentation_ai_config.py | 101 ++ ...uery_presentation_ai_config_description.py | 70 + ..._query_presentation_ai_config_sub_title.py | 70 + ...ut_query_presentation_chart_type_type_1.py | 87 ++ ...y_presentation_chart_type_type_2_type_1.py | 91 ++ ...y_presentation_chart_type_type_3_type_1.py | 91 ++ .../models/documents_put_response.py | 91 ++ .../models/documents_revoke_permits_body.py | 85 ++ .../documents_transfer_ownership_body.py | 62 + .../models/documents_update_body.py | 101 ++ ...cuments_update_permission_settings_body.py | 154 ++ ...mission_settings_body_organization_role.py | 22 + .../models/documents_update_permits_body.py | 114 ++ .../documents_update_permits_body_role.py | 17 + .../models/documents_update_response.py | 91 ++ .../models/documents_upgrade_layout_body.py | 62 + .../documents_upgrade_layout_response.py | 69 + .../models/documents_v2_create_body.py | 280 ++++ .../models/documents_v2_create_draft_body.py | 209 +++ .../models/documents_v2_create_response.py | 84 ++ .../models/documents_v2_get_draft_pretty.py | 16 + .../models/documents_v2_get_pretty.py | 16 + .../models/documents_v2_patch_draft_body.py | 174 +++ .../documents_v2_patch_draft_response.py | 92 ++ .../documents_v2_publish_draft_response.py | 84 ++ .../models/documents_v2_read_response.py | 163 +++ .../documents_v2_update_identifier_body.py | 43 + ...documents_v2_update_identifier_response.py | 84 ++ omni_python_sdk/models/email_recipient.py | 77 + .../models/embed_sso_generate_session_body.py | 106 ++ ...o_generate_session_body_user_attributes.py | 47 + .../embed_sso_generate_session_response.py | 61 + omni_python_sdk/models/eval_api_error_400.py | 69 + omni_python_sdk/models/eval_api_error_401.py | 70 + omni_python_sdk/models/eval_api_error_403.py | 70 + omni_python_sdk/models/eval_api_error_404.py | 69 + omni_python_sdk/models/eval_api_error_422.py | 70 + omni_python_sdk/models/eval_api_error_429.py | 70 + omni_python_sdk/models/eval_api_error_500.py | 70 + omni_python_sdk/models/eval_api_error_503.py | 70 + omni_python_sdk/models/eval_prompt.py | 115 ++ omni_python_sdk/models/eval_prompt_set.py | 161 +++ .../models/eval_prompt_set_list_item.py | 162 +++ .../models/eval_prompt_sets_create_body.py | 130 ++ ...al_prompt_sets_create_body_prompts_item.py | 85 ++ .../eval_prompt_sets_create_response.py | 67 + .../eval_prompt_sets_delete_response.py | 70 + .../models/eval_prompt_sets_get_response.py | 67 + .../models/eval_prompt_sets_list_response.py | 75 + .../eval_prompt_sets_unarchive_response.py | 67 + .../models/eval_prompt_sets_update_body.py | 111 ++ ...al_prompt_sets_update_body_prompts_item.py | 103 ++ .../eval_prompt_sets_update_response.py | 67 + omni_python_sdk/models/eval_run_detail.py | 212 +++ .../models/eval_run_detail_status.py | 15 + omni_python_sdk/models/eval_run_list_item.py | 202 +++ .../models/eval_run_list_item_status.py | 15 + omni_python_sdk/models/eval_run_result.py | 236 +++ .../models/eval_run_result_agentic_job.py | 102 ++ .../eval_run_result_agentic_job_state.py | 18 + omni_python_sdk/models/eval_run_stats.py | 70 + .../models/eval_runs_cancel_response.py | 83 ++ .../models/eval_runs_create_body.py | 107 ++ .../eval_runs_create_body_run_config.py | 71 + .../models/eval_runs_create_response.py | 77 + .../models/eval_runs_delete_response.py | 61 + .../models/eval_runs_get_response.py | 67 + .../models/eval_runs_list_response.py | 76 + .../models/eval_runs_unarchive_response.py | 61 + .../models/folders_add_permissions_body.py | 90 ++ .../folders_add_permissions_body_role.py | 17 + .../folders_add_permissions_response.py | 61 + omni_python_sdk/models/folders_create_body.py | 113 ++ .../models/folders_create_body_scope.py | 14 + .../models/folders_create_response.py | 96 ++ .../models/folders_create_response_scope.py | 14 + .../models/folders_delete_response.py | 61 + .../folders_get_permissions_response.py | 75 + ...s_get_permissions_response_permits_item.py | 98 ++ .../models/folders_list_response.py | 85 ++ .../folders_list_response_records_item.py | 129 ++ ...olders_list_response_records_item_count.py | 70 + omni_python_sdk/models/folders_list_scope.py | 14 + .../models/folders_list_sort_direction.py | 14 + .../models/folders_list_sort_field.py | 17 + .../models/folders_revoke_permissions_body.py | 66 + .../folders_revoke_permissions_response.py | 61 + omni_python_sdk/models/folders_update_body.py | 82 ++ .../models/folders_update_permissions_body.py | 95 ++ .../folders_update_permissions_body_role.py | 17 + .../folders_update_permissions_response.py | 61 + .../models/folders_update_response.py | 78 + omni_python_sdk/models/grid_container.py | 50 + .../models/ignore_suggestion_body.py | 43 + .../models/internal_folder_type_0.py | 88 ++ .../models/job_created_response.py | 62 + .../models/jobs_get_status_response.py | 79 ++ .../models/jobs_get_status_response_status.py | 15 + omni_python_sdk/models/json_value.py | 47 + omni_python_sdk/models/labels_create_body.py | 121 ++ .../models/labels_create_response.py | 114 ++ omni_python_sdk/models/labels_get_response.py | 114 ++ .../models/labels_list_response.py | 75 + .../labels_list_response_labels_item.py | 114 ++ omni_python_sdk/models/labels_update_body.py | 120 ++ .../models/labels_update_response.py | 114 ++ omni_python_sdk/models/model_suggestion.py | 235 +++ .../models/model_suggestions_list_response.py | 85 ++ .../models/model_suggestions_list_status.py | 15 + .../models/model_yaml_create_request_body.py | 126 ++ .../model_yaml_create_request_body_mode.py | 17 + omni_python_sdk/models/model_yaml_response.py | 113 ++ .../models/model_yaml_response_checksums.py | 47 + .../models/model_yaml_response_files.py | 47 + .../models/model_yaml_response_view_names.py | 47 + .../models/models_branch_dbt_body.py | 74 + .../models/models_cache_reset_body.py | 61 + .../models/models_cache_reset_response.py | 75 + ...models_cache_reset_response_cache_reset.py | 113 ++ omni_python_sdk/models/models_commit_body.py | 94 ++ .../models/models_commit_response.py | 98 ++ .../models_content_validator_get_find_type.py | 15 + .../models_content_validator_get_response.py | 109 ++ ...nt_validator_get_response_branch_type_0.py | 70 + .../models_content_validator_replace_body.py | 151 ++ ...dator_replace_body_find_or_replace_type.py | 21 + ...dels_content_validator_replace_response.py | 101 ++ .../models/models_create_field_body.py | 148 ++ ...models_create_field_body_aggregate_type.py | 41 + .../models_create_models_create_response.py | 104 ++ ...els_create_models_create_response_model.py | 85 ++ .../models/models_dbt_exposures_response.py | 85 ++ .../models_dbt_exposures_sort_direction.py | 14 + .../models/models_delete_topic_mode.py | 15 + .../models/models_delete_view_mode.py | 15 + .../models/models_get_schemas_response.py | 62 + .../models/models_get_topic_response.py | 75 + .../models/models_get_topic_response_topic.py | 150 ++ ...topic_response_topic_relationships_item.py | 47 + ...els_get_topic_response_topic_views_item.py | 47 + .../models/models_get_view_response.py | 83 ++ .../models_get_view_response_views_item.py | 112 ++ ...et_view_response_views_item_fields_item.py | 74 + ...ew_response_views_item_fields_item_type.py | 19 + .../models/models_git_create_body.py | 195 +++ .../models_git_create_body_auth_method.py | 14 + ...ls_git_create_body_git_service_provider.py | 22 + ...ls_git_create_body_require_pull_request.py | 17 + .../models/models_git_create_response.py | 194 +++ .../models_git_create_response_auth_method.py | 14 + ...it_create_response_require_pull_request.py | 17 + .../models/models_git_delete_response.py | 69 + .../models/models_git_get_response.py | 194 +++ .../models_git_get_response_auth_method.py | 14 + ...s_git_get_response_require_pull_request.py | 17 + .../models/models_git_sync_body.py | 61 + .../models/models_git_sync_response.py | 91 ++ .../models/models_git_update_body.py | 187 +++ .../models_git_update_body_auth_method.py | 14 + ...ls_git_update_body_git_service_provider.py | 22 + ...ls_git_update_body_require_pull_request.py | 17 + .../models/models_git_update_response.py | 194 +++ .../models_git_update_response_auth_method.py | 14 + ...it_update_response_require_pull_request.py | 17 + .../models/models_list_include_deleted.py | 16 + .../models/models_list_model_kind.py | 18 + .../models/models_list_response.py | 85 ++ .../models_list_response_records_item.py | 177 +++ ...ist_response_records_item_branches_item.py | 69 + .../models/models_list_sort_direction.py | 14 + .../models/models_list_sort_field.py | 18 + .../models/models_list_topics_response.py | 83 ++ ...models_list_topics_response_topics_item.py | 107 ++ .../models/models_merge_branch_body.py | 88 ++ .../models/models_merge_branch_response.py | 85 ++ omni_python_sdk/models/models_migrate_body.py | 103 ++ .../models/models_refresh_hard_refresh.py | 14 + .../models/models_refresh_response.py | 79 ++ .../models/models_refresh_response_status.py | 15 + omni_python_sdk/models/models_update_body.py | 61 + .../models/models_update_field_body.py | 302 ++++ .../models_update_field_body_filters.py | 47 + ...ls_update_field_body_group_filters_item.py | 47 + .../models/models_update_response.py | 75 + .../models/models_update_response_model.py | 71 + .../models/models_update_topic_body.py | 97 ++ .../models/models_update_view_body.py | 108 ++ .../models/models_validate_response.py | 83 ++ .../models_validate_response_issues_item.py | 93 ++ ..._validate_response_issues_item_severity.py | 16 + .../models/models_yaml_delete_mode.py | 17 + .../models/models_yaml_get_mode.py | 17 + omni_python_sdk/models/owner_internal.py | 70 + omni_python_sdk/models/page_container.py | 50 + omni_python_sdk/models/page_info.py | 91 ++ .../query_presentation_patch_external.py | 47 + .../query_presentation_read_external.py | 47 + .../query_presentations_patch_external.py | 47 + .../query_presentations_read_external.py | 47 + omni_python_sdk/models/query_run_body.py | 174 +++ .../models/query_run_body_cache.py | 16 + .../models/query_run_body_result_type.py | 15 + omni_python_sdk/models/query_run_response.py | 84 ++ .../models/query_timeout_response.py | 83 ++ omni_python_sdk/models/query_wait_response.py | 61 + omni_python_sdk/models/reference_container.py | 50 + .../models/role_assignment_result.py | 165 +++ omni_python_sdk/models/role_origin_type_0.py | 63 + .../models/role_origin_type_0_type.py | 13 + omni_python_sdk/models/role_origin_type_1.py | 63 + .../models/role_origin_type_1_type.py | 13 + omni_python_sdk/models/role_origin_type_2.py | 63 + .../models/role_origin_type_2_type.py | 13 + omni_python_sdk/models/role_origin_type_3.py | 87 ++ .../models/role_origin_type_3_type.py | 13 + omni_python_sdk/models/routine_create_body.py | 159 +++ .../models/routine_create_response.py | 62 + .../models/routine_delete_response.py | 70 + .../models/routine_email_destination.py | 82 ++ .../routine_email_destination_response.py | 76 + ...routine_email_destination_response_type.py | 13 + .../models/routine_email_destination_type.py | 13 + .../models/routine_last_run_type_0.py | 85 ++ omni_python_sdk/models/routine_response.py | 279 ++++ .../models/routine_slack_destination.py | 67 + ..._slack_destination_slack_recipient_type.py | 16 + .../models/routine_slack_destination_type.py | 13 + .../models/routine_trigger_response.py | 62 + omni_python_sdk/models/routine_update_body.py | 137 ++ .../models/routines_list_response.py | 85 ++ .../models/routines_list_sort_direction.py | 14 + .../models/schedule_suggestions_body.py | 43 + .../models/schedule_suggestions_response.py | 91 ++ .../schedule_suggestions_response_status.py | 13 + .../models/schedules_add_recipients_body.py | 110 ++ .../schedules_add_recipients_response.py | 77 + .../schedules_create_schedules_create_body.py | 340 +++++ ...te_schedules_create_body_condition_type.py | 22 + ..._schedules_create_body_destination_type.py | 23 + ...les_create_schedules_create_body_format.py | 20 + ...e_schedules_create_body_recipients_item.py | 61 + ...edules_create_schedules_create_response.py | 111 ++ .../models/schedules_get_destination.py | 151 ++ .../models/schedules_get_recipient.py | 84 ++ .../schedules_get_recipient_membership.py | 67 + ...schedules_get_recipient_membership_user.py | 75 + .../models/schedules_get_response.py | 294 ++++ .../models/schedules_get_response_owner.py | 61 + .../models/schedules_list_content_type.py | 14 + .../models/schedules_list_destination.py | 18 + omni_python_sdk/models/schedules_list_item.py | 296 ++++ .../models/schedules_list_item_alert.py | 77 + .../models/schedules_list_response_200.py | 85 ++ .../models/schedules_list_schedule_type.py | 14 + .../models/schedules_list_sort_direction.py | 14 + .../models/schedules_list_sort_field.py | 17 + .../models/schedules_list_status.py | 16 + .../schedules_recipients_get_response.py | 118 ++ .../schedules_recipients_get_response_type.py | 18 + .../schedules_remove_recipients_body.py | 110 ++ .../schedules_remove_recipients_response.py | 77 + .../schedules_transfer_ownership_body.py | 64 + omni_python_sdk/models/scim_group_response.py | 106 ++ .../scim_group_response_members_item.py | 70 + .../models/scim_groups_create_body.py | 90 ++ .../scim_groups_create_body_members_item.py | 62 + .../scim_groups_get_excluded_attributes.py | 13 + .../scim_groups_list_excluded_attributes.py | 13 + .../models/scim_groups_list_response.py | 107 ++ .../models/scim_groups_patch_body.py | 160 +++ ...roups_patch_body_operations_item_type_0.py | 82 ++ ...ps_patch_body_operations_item_type_0_op.py | 16 + ...patch_body_operations_item_type_0_value.py | 72 + ...roups_patch_body_operations_item_type_1.py | 74 + ...ps_patch_body_operations_item_type_1_op.py | 16 + ...roups_patch_body_operations_item_type_2.py | 104 ++ ...ps_patch_body_operations_item_type_2_op.py | 16 + ..._patch_body_operations_item_type_2_path.py | 15 + ..._body_operations_item_type_2_value_item.py | 73 + ...roups_patch_body_operations_item_type_3.py | 122 ++ ...ps_patch_body_operations_item_type_3_op.py | 16 + ..._patch_body_operations_item_type_3_path.py | 16 + ...perations_item_type_3_value_type_0_item.py | 73 + .../scim_groups_patch_body_schemas_item.py | 13 + .../models/scim_groups_replace_body.py | 83 ++ .../scim_groups_replace_body_members_item.py | 70 + .../models/scim_user_create_request.py | 100 ++ ...request_urnomniparams_10_user_attribute.py | 156 ++ ...er_attribute_additional_property_type_6.py | 47 + .../models/scim_user_patch_request.py | 96 ++ ...scim_user_patch_request_operations_item.py | 141 ++ ...m_user_patch_request_operations_item_op.py | 20 + ...ch_request_operations_item_value_type_6.py | 151 ++ ...sscimschemasextensionenterprise_20_user.py | 159 +++ ...rise_20_user_additional_property_type_6.py | 50 + ..._type_6_urnomniparams_10_user_attribute.py | 160 +++ ...er_attribute_additional_property_type_6.py | 49 + .../scim_user_patch_request_schemas_item.py | 13 + .../models/scim_user_put_request.py | 146 ++ ...sscimschemasextensionenterprise_20_user.py | 160 +++ ...rise_20_user_additional_property_type_6.py | 47 + ...request_urnomniparams_10_user_attribute.py | 156 ++ ...er_attribute_additional_property_type_6.py | 47 + omni_python_sdk/models/scim_user_response.py | 94 ++ .../models/scim_users_list_response.py | 107 ++ .../models/settings_patch_external.py | 216 +++ ...tings_patch_external_custom_text_type_0.py | 72 + ...gs_patch_external_run_queries_on_type_1.py | 16 + ...h_external_run_queries_on_type_2_type_1.py | 18 + ...h_external_run_queries_on_type_3_type_1.py | 18 + .../models/settings_read_external.py | 195 +++ ...ttings_read_external_custom_text_type_0.py | 72 + ...ngs_read_external_run_queries_on_type_1.py | 16 + ...d_external_run_queries_on_type_2_type_1.py | 16 + ...d_external_run_queries_on_type_3_type_1.py | 16 + omni_python_sdk/models/stack_container.py | 50 + omni_python_sdk/models/success_response.py | 61 + .../models/suggestion_context_edit.py | 94 ++ .../models/suggestion_evidence_item.py | 80 ++ .../models/suggestion_evidence_item_type.py | 13 + .../models/suggestion_proposed_changes.py | 89 ++ .../suggestion_proposed_changes_kind.py | 13 + omni_python_sdk/models/upload.py | 190 +++ omni_python_sdk/models/upload_create_body.py | 129 ++ .../models/upload_create_response.py | 118 ++ .../models/upload_delete_response.py | 61 + .../models/upload_uploaded_by_user_type_0.py | 71 + .../models/uploads_list_response.py | 85 ++ .../models/uploads_list_sort_direction.py | 14 + .../models/uploads_list_sort_field.py | 15 + omni_python_sdk/models/uploads_list_type.py | 14 + .../models/user_attributes_list_response.py | 76 + ...r_attributes_list_response_records_item.py | 166 +++ ...ributes_list_response_records_item_type.py | 16 + .../models/user_group_recipient.py | 91 ++ .../user_group_role_assignment_result.py | 108 ++ .../models/user_group_role_origin.py | 88 ++ .../models/user_group_role_origin_type.py | 13 + .../user_groups_assign_model_role_body.py | 98 ++ .../user_groups_assign_model_role_response.py | 86 ++ .../user_groups_get_model_roles_response.py | 83 ++ .../models/users_assign_model_role_body.py | 98 ++ .../users_assign_model_role_response.py | 86 ++ .../models/users_create_email_only_body.py | 85 ++ ..._create_email_only_body_user_attributes.py | 60 + .../users_create_email_only_bulk_body.py | 75 + ..._create_email_only_bulk_body_users_item.py | 90 ++ ...ly_bulk_body_users_item_user_attributes.py | 60 + .../users_create_email_only_bulk_response.py | 77 + ...e_email_only_bulk_response_results_item.py | 70 + .../users_create_email_only_response.py | 70 + .../models/users_get_model_roles_response.py | 84 ++ .../models/users_list_email_only_response.py | 85 ++ ...s_list_email_only_response_records_item.py | 88 ++ ...y_response_records_item_user_attributes.py | 47 + .../users_list_email_only_sort_direction.py | 14 + omni_python_sdk/models/whoami_model_role.py | 104 ++ .../whoami_model_role_permissions_item.py | 41 + omni_python_sdk/models/whoami_response.py | 109 ++ .../models/whoami_response_key_scope.py | 14 + .../models/whoami_response_org_role.py | 14 + .../models/whoami_response_roles_by_model.py | 63 + omni_python_sdk/models/whoami_user.py | 70 + omni_python_sdk/py.typed | 1 + omni_python_sdk/types.py | 54 + 820 files changed, 88153 insertions(+), 781 deletions(-) delete mode 100644 omni_python_sdk/api.py create mode 100644 omni_python_sdk/api/__init__.py create mode 100644 omni_python_sdk/api/ai/__init__.py create mode 100644 omni_python_sdk/api/ai/ai_branding.py create mode 100644 omni_python_sdk/api/ai/ai_conversation_detail.py create mode 100644 omni_python_sdk/api/ai/ai_conversations_list.py create mode 100644 omni_python_sdk/api/ai/ai_credit_controls_get.py create mode 100644 omni_python_sdk/api/ai/ai_credit_controls_update.py create mode 100644 omni_python_sdk/api/ai/ai_credit_controls_users_list.py create mode 100644 omni_python_sdk/api/ai/ai_credit_controls_users_update.py create mode 100644 omni_python_sdk/api/ai/ai_generate_query.py create mode 100644 omni_python_sdk/api/ai/ai_job_cancel.py create mode 100644 omni_python_sdk/api/ai/ai_job_result.py create mode 100644 omni_python_sdk/api/ai/ai_job_status.py create mode 100644 omni_python_sdk/api/ai/ai_job_submit.py create mode 100644 omni_python_sdk/api/ai/ai_job_visualization.py create mode 100644 omni_python_sdk/api/ai/ai_pick_topic.py create mode 100644 omni_python_sdk/api/ai/ai_search_omni_docs.py create mode 100644 omni_python_sdk/api/ai_eval/__init__.py create mode 100644 omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_archive.py create mode 100644 omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_create.py create mode 100644 omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_get.py create mode 100644 omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_list.py create mode 100644 omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_unarchive.py create mode 100644 omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_update.py create mode 100644 omni_python_sdk/api/ai_eval/ai_eval_runs_archive.py create mode 100644 omni_python_sdk/api/ai_eval/ai_eval_runs_cancel.py create mode 100644 omni_python_sdk/api/ai_eval/ai_eval_runs_create.py create mode 100644 omni_python_sdk/api/ai_eval/ai_eval_runs_get.py create mode 100644 omni_python_sdk/api/ai_eval/ai_eval_runs_list.py create mode 100644 omni_python_sdk/api/ai_eval/ai_eval_runs_unarchive.py create mode 100644 omni_python_sdk/api/ai_model_suggestions/__init__.py create mode 100644 omni_python_sdk/api/ai_model_suggestions/model_suggestions_delete.py create mode 100644 omni_python_sdk/api/ai_model_suggestions/model_suggestions_ignore.py create mode 100644 omni_python_sdk/api/ai_model_suggestions/model_suggestions_list.py create mode 100644 omni_python_sdk/api/ai_model_suggestions/model_suggestions_restore.py create mode 100644 omni_python_sdk/api/ai_model_suggestions/model_suggestions_schedule_disable.py create mode 100644 omni_python_sdk/api/ai_model_suggestions/model_suggestions_schedule_enable.py create mode 100644 omni_python_sdk/api/ai_routines/__init__.py create mode 100644 omni_python_sdk/api/ai_routines/routine_create.py create mode 100644 omni_python_sdk/api/ai_routines/routine_delete.py create mode 100644 omni_python_sdk/api/ai_routines/routine_get.py create mode 100644 omni_python_sdk/api/ai_routines/routine_trigger.py create mode 100644 omni_python_sdk/api/ai_routines/routine_update.py create mode 100644 omni_python_sdk/api/ai_routines/routines_list.py create mode 100644 omni_python_sdk/api/api_tokens/__init__.py create mode 100644 omni_python_sdk/api/api_tokens/api_keys_delete.py create mode 100644 omni_python_sdk/api/api_tokens/api_keys_get.py create mode 100644 omni_python_sdk/api/api_tokens/api_keys_list.py create mode 100644 omni_python_sdk/api/api_tokens/api_keys_update.py create mode 100644 omni_python_sdk/api/connections/__init__.py create mode 100644 omni_python_sdk/api/connections/connection_environments_create.py create mode 100644 omni_python_sdk/api/connections/connection_environments_delete.py create mode 100644 omni_python_sdk/api/connections/connection_environments_update.py create mode 100644 omni_python_sdk/api/connections/connections_create.py create mode 100644 omni_python_sdk/api/connections/connections_dbt_delete.py create mode 100644 omni_python_sdk/api/connections/connections_dbt_environments_create.py create mode 100644 omni_python_sdk/api/connections/connections_dbt_environments_delete.py create mode 100644 omni_python_sdk/api/connections/connections_dbt_environments_list.py create mode 100644 omni_python_sdk/api/connections/connections_dbt_environments_update.py create mode 100644 omni_python_sdk/api/connections/connections_dbt_get.py create mode 100644 omni_python_sdk/api/connections/connections_dbt_update.py create mode 100644 omni_python_sdk/api/connections/connections_delete.py create mode 100644 omni_python_sdk/api/connections/connections_get.py create mode 100644 omni_python_sdk/api/connections/connections_list.py create mode 100644 omni_python_sdk/api/connections/connections_schedules_create.py create mode 100644 omni_python_sdk/api/connections/connections_schedules_delete.py create mode 100644 omni_python_sdk/api/connections/connections_schedules_get.py create mode 100644 omni_python_sdk/api/connections/connections_schedules_list.py create mode 100644 omni_python_sdk/api/connections/connections_schedules_update.py create mode 100644 omni_python_sdk/api/connections/connections_update.py create mode 100644 omni_python_sdk/api/content/__init__.py create mode 100644 omni_python_sdk/api/content/content_list.py create mode 100644 omni_python_sdk/api/dashboards/__init__.py create mode 100644 omni_python_sdk/api/dashboards/dashboards_download.py create mode 100644 omni_python_sdk/api/dashboards/dashboards_download_file.py create mode 100644 omni_python_sdk/api/dashboards/dashboards_download_status.py create mode 100644 omni_python_sdk/api/dashboards/dashboards_get_filters.py create mode 100644 omni_python_sdk/api/dashboards/dashboards_update_filters.py create mode 100644 omni_python_sdk/api/documents/__init__.py create mode 100644 omni_python_sdk/api/documents/documents_access_list.py create mode 100644 omni_python_sdk/api/documents/documents_add_favorite.py create mode 100644 omni_python_sdk/api/documents/documents_add_label.py create mode 100644 omni_python_sdk/api/documents/documents_add_permits.py create mode 100644 omni_python_sdk/api/documents/documents_bulk_update_labels.py create mode 100644 omni_python_sdk/api/documents/documents_create.py create mode 100644 omni_python_sdk/api/documents/documents_create_draft.py create mode 100644 omni_python_sdk/api/documents/documents_delete.py create mode 100644 omni_python_sdk/api/documents/documents_discard_draft.py create mode 100644 omni_python_sdk/api/documents/documents_duplicate.py create mode 100644 omni_python_sdk/api/documents/documents_get.py create mode 100644 omni_python_sdk/api/documents/documents_get_permissions.py create mode 100644 omni_python_sdk/api/documents/documents_get_queries.py create mode 100644 omni_python_sdk/api/documents/documents_list.py create mode 100644 omni_python_sdk/api/documents/documents_list_drafts.py create mode 100644 omni_python_sdk/api/documents/documents_list_favorites.py create mode 100644 omni_python_sdk/api/documents/documents_move.py create mode 100644 omni_python_sdk/api/documents/documents_put.py create mode 100644 omni_python_sdk/api/documents/documents_remove_favorite.py create mode 100644 omni_python_sdk/api/documents/documents_remove_label.py create mode 100644 omni_python_sdk/api/documents/documents_revoke_permits.py create mode 100644 omni_python_sdk/api/documents/documents_transfer_ownership.py create mode 100644 omni_python_sdk/api/documents/documents_update.py create mode 100644 omni_python_sdk/api/documents/documents_update_permission_settings.py create mode 100644 omni_python_sdk/api/documents/documents_update_permits.py create mode 100644 omni_python_sdk/api/documents/documents_upgrade_layout.py create mode 100644 omni_python_sdk/api/documents/documents_v2_create.py create mode 100644 omni_python_sdk/api/documents/documents_v2_get.py create mode 100644 omni_python_sdk/api/documents/documents_v2_get_draft.py create mode 100644 omni_python_sdk/api/documents/documents_v2_patch_draft.py create mode 100644 omni_python_sdk/api/documents/documents_v2_patch_draft_by_identifier.py create mode 100644 omni_python_sdk/api/documents/documents_v2_publish_draft.py create mode 100644 omni_python_sdk/api/documents/documents_v2_update_identifier.py create mode 100644 omni_python_sdk/api/embed/__init__.py create mode 100644 omni_python_sdk/api/embed/embed_sso_generate_session.py create mode 100644 omni_python_sdk/api/folders/__init__.py create mode 100644 omni_python_sdk/api/folders/folders_add_permissions.py create mode 100644 omni_python_sdk/api/folders/folders_create.py create mode 100644 omni_python_sdk/api/folders/folders_delete.py create mode 100644 omni_python_sdk/api/folders/folders_get_permissions.py create mode 100644 omni_python_sdk/api/folders/folders_list.py create mode 100644 omni_python_sdk/api/folders/folders_revoke_permissions.py create mode 100644 omni_python_sdk/api/folders/folders_update.py create mode 100644 omni_python_sdk/api/folders/folders_update_permissions.py create mode 100644 omni_python_sdk/api/labels/__init__.py create mode 100644 omni_python_sdk/api/labels/labels_create.py create mode 100644 omni_python_sdk/api/labels/labels_delete.py create mode 100644 omni_python_sdk/api/labels/labels_get.py create mode 100644 omni_python_sdk/api/labels/labels_list.py create mode 100644 omni_python_sdk/api/labels/labels_update.py create mode 100644 omni_python_sdk/api/models/__init__.py create mode 100644 omni_python_sdk/api/models/jobs_get_status.py create mode 100644 omni_python_sdk/api/models/model_ai_agent_actions.py create mode 100644 omni_python_sdk/api/models/models_branch_dbt.py create mode 100644 omni_python_sdk/api/models/models_cache_reset.py create mode 100644 omni_python_sdk/api/models/models_commit.py create mode 100644 omni_python_sdk/api/models/models_content_validator_get.py create mode 100644 omni_python_sdk/api/models/models_content_validator_replace.py create mode 100644 omni_python_sdk/api/models/models_create.py create mode 100644 omni_python_sdk/api/models/models_create_field.py create mode 100644 omni_python_sdk/api/models/models_dbt_exposures.py create mode 100644 omni_python_sdk/api/models/models_dbt_sync.py create mode 100644 omni_python_sdk/api/models/models_delete_branch.py create mode 100644 omni_python_sdk/api/models/models_delete_field.py create mode 100644 omni_python_sdk/api/models/models_delete_topic.py create mode 100644 omni_python_sdk/api/models/models_delete_view.py create mode 100644 omni_python_sdk/api/models/models_get_schemas.py create mode 100644 omni_python_sdk/api/models/models_get_topic.py create mode 100644 omni_python_sdk/api/models/models_get_views.py create mode 100644 omni_python_sdk/api/models/models_git_create.py create mode 100644 omni_python_sdk/api/models/models_git_delete.py create mode 100644 omni_python_sdk/api/models/models_git_get.py create mode 100644 omni_python_sdk/api/models/models_git_sync.py create mode 100644 omni_python_sdk/api/models/models_git_update.py create mode 100644 omni_python_sdk/api/models/models_list.py create mode 100644 omni_python_sdk/api/models/models_list_topics.py create mode 100644 omni_python_sdk/api/models/models_merge_branch.py create mode 100644 omni_python_sdk/api/models/models_migrate.py create mode 100644 omni_python_sdk/api/models/models_refresh.py create mode 100644 omni_python_sdk/api/models/models_update.py create mode 100644 omni_python_sdk/api/models/models_update_field.py create mode 100644 omni_python_sdk/api/models/models_update_topic.py create mode 100644 omni_python_sdk/api/models/models_update_view.py create mode 100644 omni_python_sdk/api/models/models_validate.py create mode 100644 omni_python_sdk/api/models/models_yaml_create.py create mode 100644 omni_python_sdk/api/models/models_yaml_delete.py create mode 100644 omni_python_sdk/api/models/models_yaml_get.py create mode 100644 omni_python_sdk/api/query/__init__.py create mode 100644 omni_python_sdk/api/query/query_run.py create mode 100644 omni_python_sdk/api/query/query_wait.py create mode 100644 omni_python_sdk/api/schedules/__init__.py create mode 100644 omni_python_sdk/api/schedules/schedules_add_recipients.py create mode 100644 omni_python_sdk/api/schedules/schedules_create.py create mode 100644 omni_python_sdk/api/schedules/schedules_delete.py create mode 100644 omni_python_sdk/api/schedules/schedules_get.py create mode 100644 omni_python_sdk/api/schedules/schedules_list.py create mode 100644 omni_python_sdk/api/schedules/schedules_pause.py create mode 100644 omni_python_sdk/api/schedules/schedules_recipients_get.py create mode 100644 omni_python_sdk/api/schedules/schedules_remove_recipients.py create mode 100644 omni_python_sdk/api/schedules/schedules_resume.py create mode 100644 omni_python_sdk/api/schedules/schedules_transfer_ownership.py create mode 100644 omni_python_sdk/api/schedules/schedules_trigger.py create mode 100644 omni_python_sdk/api/schedules/schedules_update.py create mode 100644 omni_python_sdk/api/scim/__init__.py create mode 100644 omni_python_sdk/api/scim/scim_embed_users_delete.py create mode 100644 omni_python_sdk/api/scim/scim_embed_users_get.py create mode 100644 omni_python_sdk/api/scim/scim_embed_users_list.py create mode 100644 omni_python_sdk/api/scim/scim_groups_create.py create mode 100644 omni_python_sdk/api/scim/scim_groups_delete.py create mode 100644 omni_python_sdk/api/scim/scim_groups_get.py create mode 100644 omni_python_sdk/api/scim/scim_groups_list.py create mode 100644 omni_python_sdk/api/scim/scim_groups_replace.py create mode 100644 omni_python_sdk/api/scim/scim_groups_update.py create mode 100644 omni_python_sdk/api/scim/scim_users_create.py create mode 100644 omni_python_sdk/api/scim/scim_users_delete.py create mode 100644 omni_python_sdk/api/scim/scim_users_get.py create mode 100644 omni_python_sdk/api/scim/scim_users_list.py create mode 100644 omni_python_sdk/api/scim/scim_users_replace.py create mode 100644 omni_python_sdk/api/scim/scim_users_update.py create mode 100644 omni_python_sdk/api/unstable/__init__.py create mode 100644 omni_python_sdk/api/unstable/unstable_documents_export.py create mode 100644 omni_python_sdk/api/unstable/unstable_documents_import.py create mode 100644 omni_python_sdk/api/uploads/__init__.py create mode 100644 omni_python_sdk/api/uploads/uploads_create.py create mode 100644 omni_python_sdk/api/uploads/uploads_delete.py create mode 100644 omni_python_sdk/api/uploads/uploads_list.py create mode 100644 omni_python_sdk/api/user_attributes/__init__.py create mode 100644 omni_python_sdk/api/user_attributes/user_attributes_list.py create mode 100644 omni_python_sdk/api/users/__init__.py create mode 100644 omni_python_sdk/api/users/user_groups_assign_model_role.py create mode 100644 omni_python_sdk/api/users/user_groups_get_model_roles.py create mode 100644 omni_python_sdk/api/users/users_assign_model_role.py create mode 100644 omni_python_sdk/api/users/users_create_email_only.py create mode 100644 omni_python_sdk/api/users/users_create_email_only_bulk.py create mode 100644 omni_python_sdk/api/users/users_get_model_roles.py create mode 100644 omni_python_sdk/api/users/users_list_email_only.py create mode 100644 omni_python_sdk/api/whoami/__init__.py create mode 100644 omni_python_sdk/api/whoami/whoami.py create mode 100644 omni_python_sdk/client.py create mode 100644 omni_python_sdk/errors.py create mode 100644 omni_python_sdk/models/__init__.py create mode 100644 omni_python_sdk/models/ai_agent_action.py create mode 100644 omni_python_sdk/models/ai_agent_action_kind.py create mode 100644 omni_python_sdk/models/ai_agent_actions_response.py create mode 100644 omni_python_sdk/models/ai_branding_response.py create mode 100644 omni_python_sdk/models/ai_conversation.py create mode 100644 omni_python_sdk/models/ai_conversation_detail_response.py create mode 100644 omni_python_sdk/models/ai_conversation_message.py create mode 100644 omni_python_sdk/models/ai_conversation_message_role.py create mode 100644 omni_python_sdk/models/ai_conversations_list_response.py create mode 100644 omni_python_sdk/models/ai_credit_controls_response.py create mode 100644 omni_python_sdk/models/ai_credit_controls_update_body.py create mode 100644 omni_python_sdk/models/ai_credit_controls_users_list_response.py create mode 100644 omni_python_sdk/models/ai_credit_controls_users_list_response_records_item.py create mode 100644 omni_python_sdk/models/ai_credit_shutoff_error.py create mode 100644 omni_python_sdk/models/ai_credit_shutoff_error_code.py create mode 100644 omni_python_sdk/models/ai_eval_prompt_sets_list_archived.py create mode 100644 omni_python_sdk/models/ai_eval_runs_list_archived.py create mode 100644 omni_python_sdk/models/ai_generate_query_body.py create mode 100644 omni_python_sdk/models/ai_generate_query_response.py create mode 100644 omni_python_sdk/models/ai_generate_query_response_error_type_0.py create mode 100644 omni_python_sdk/models/ai_generate_query_response_result.py create mode 100644 omni_python_sdk/models/ai_job_action.py create mode 100644 omni_python_sdk/models/ai_job_action_query_result.py create mode 100644 omni_python_sdk/models/ai_job_action_query_result_query.py create mode 100644 omni_python_sdk/models/ai_job_action_query_result_status.py create mode 100644 omni_python_sdk/models/ai_job_cancel_response.py create mode 100644 omni_python_sdk/models/ai_job_cancel_response_state.py create mode 100644 omni_python_sdk/models/ai_job_result_response.py create mode 100644 omni_python_sdk/models/ai_job_status_response.py create mode 100644 omni_python_sdk/models/ai_job_status_response_error.py create mode 100644 omni_python_sdk/models/ai_job_status_response_progress_type_0.py create mode 100644 omni_python_sdk/models/ai_job_status_response_state.py create mode 100644 omni_python_sdk/models/ai_job_submit_body.py create mode 100644 omni_python_sdk/models/ai_job_submit_body_webhook_metadata.py create mode 100644 omni_python_sdk/models/ai_job_submit_response.py create mode 100644 omni_python_sdk/models/ai_pick_topic_body.py create mode 100644 omni_python_sdk/models/ai_pick_topic_response.py create mode 100644 omni_python_sdk/models/ai_query_sort.py create mode 100644 omni_python_sdk/models/ai_search_omni_docs_body.py create mode 100644 omni_python_sdk/models/ai_search_omni_docs_response.py create mode 100644 omni_python_sdk/models/ai_search_omni_docs_response_sources_item.py create mode 100644 omni_python_sdk/models/ai_semantic_query.py create mode 100644 omni_python_sdk/models/ai_topic_params.py create mode 100644 omni_python_sdk/models/ai_user_credit_limit_entry.py create mode 100644 omni_python_sdk/models/ai_user_credit_limits_response.py create mode 100644 omni_python_sdk/models/ai_user_credit_limits_response_users_item.py create mode 100644 omni_python_sdk/models/ai_user_credit_limits_update_body.py create mode 100644 omni_python_sdk/models/api_document.py create mode 100644 omni_python_sdk/models/api_document_count.py create mode 100644 omni_python_sdk/models/api_draft.py create mode 100644 omni_python_sdk/models/api_draft_actor.py create mode 100644 omni_python_sdk/models/api_draft_branch_type_0.py create mode 100644 omni_python_sdk/models/api_draft_status.py create mode 100644 omni_python_sdk/models/api_error_400.py create mode 100644 omni_python_sdk/models/api_error_401.py create mode 100644 omni_python_sdk/models/api_error_403.py create mode 100644 omni_python_sdk/models/api_error_404.py create mode 100644 omni_python_sdk/models/api_error_409.py create mode 100644 omni_python_sdk/models/api_error_422.py create mode 100644 omni_python_sdk/models/api_error_429.py create mode 100644 omni_python_sdk/models/api_key.py create mode 100644 omni_python_sdk/models/api_key_delete_response.py create mode 100644 omni_python_sdk/models/api_key_list_response.py create mode 100644 omni_python_sdk/models/api_key_type.py create mode 100644 omni_python_sdk/models/api_key_update_body.py create mode 100644 omni_python_sdk/models/api_keys_list_sort_direction.py create mode 100644 omni_python_sdk/models/api_keys_list_sort_field.py create mode 100644 omni_python_sdk/models/api_keys_list_type.py create mode 100644 omni_python_sdk/models/api_vis_config.py create mode 100644 omni_python_sdk/models/composite_filter.py create mode 100644 omni_python_sdk/models/composite_filter_conjunction.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_0.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_0_applied_labels.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_0_kind.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_0_type.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_1.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_1_kind.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_1_type.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_2.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_2_kind.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_2_type.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_2_ui_type_type_1.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_2_ui_type_type_2_type_1.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_2_ui_type_type_3_type_1.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_3.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_3_type.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_4.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_4_type.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_5.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_5_type.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_5_view_query.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_5_view_query_filters.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_6.py create mode 100644 omni_python_sdk/models/composite_filter_filters_item_type_6_type.py create mode 100644 omni_python_sdk/models/composite_filter_type.py create mode 100644 omni_python_sdk/models/connection_environments_create_connections_environments_create_body.py create mode 100644 omni_python_sdk/models/connection_environments_create_connections_environments_create_response.py create mode 100644 omni_python_sdk/models/connection_environments_create_connections_environments_create_response_connection_environment.py create mode 100644 omni_python_sdk/models/connection_environments_delete_connections_environments_delete_response.py create mode 100644 omni_python_sdk/models/connection_environments_update_connections_environments_update_body.py create mode 100644 omni_python_sdk/models/connection_environments_update_connections_environments_update_response.py create mode 100644 omni_python_sdk/models/connections_create_connections_create_body.py create mode 100644 omni_python_sdk/models/connections_create_connections_create_body_base_role.py create mode 100644 omni_python_sdk/models/connections_create_connections_create_body_dialect.py create mode 100644 omni_python_sdk/models/connections_create_connections_create_response.py create mode 100644 omni_python_sdk/models/connections_dbt_delete_connections_dbt_delete_response.py create mode 100644 omni_python_sdk/models/connections_dbt_environments_list_sort_direction.py create mode 100644 omni_python_sdk/models/connections_dbt_environments_list_sort_field.py create mode 100644 omni_python_sdk/models/connections_dbt_get_dbt_configured_response.py create mode 100644 omni_python_sdk/models/connections_dbt_get_dbt_not_configured_response.py create mode 100644 omni_python_sdk/models/connections_dbt_update_connections_dbt_update_body.py create mode 100644 omni_python_sdk/models/connections_dbt_update_connections_dbt_update_body_project_root_path_type_1.py create mode 100644 omni_python_sdk/models/connections_dbt_update_connections_dbt_update_response.py create mode 100644 omni_python_sdk/models/connections_delete_connections_delete_response.py create mode 100644 omni_python_sdk/models/connections_get_connections_get_response.py create mode 100644 omni_python_sdk/models/connections_get_connections_get_response_connection.py create mode 100644 omni_python_sdk/models/connections_get_connections_get_response_connection_dialect.py create mode 100644 omni_python_sdk/models/connections_list_connections_list_response.py create mode 100644 omni_python_sdk/models/connections_list_connections_list_response_connection.py create mode 100644 omni_python_sdk/models/connections_list_connections_list_response_connection_dialect.py create mode 100644 omni_python_sdk/models/connections_list_sort_direction.py create mode 100644 omni_python_sdk/models/connections_list_sort_field.py create mode 100644 omni_python_sdk/models/connections_schedules_create_connections_schedules_create_body.py create mode 100644 omni_python_sdk/models/connections_schedules_create_connections_schedules_create_response.py create mode 100644 omni_python_sdk/models/connections_schedules_delete_connections_schedules_delete_response.py create mode 100644 omni_python_sdk/models/connections_schedules_get_connections_schedules_get_response.py create mode 100644 omni_python_sdk/models/connections_schedules_list_connections_schedules_list_response.py create mode 100644 omni_python_sdk/models/connections_schedules_list_connections_schedules_list_response_connection_schedule.py create mode 100644 omni_python_sdk/models/connections_schedules_update_connections_schedules_update_body.py create mode 100644 omni_python_sdk/models/connections_schedules_update_connections_schedules_update_response.py create mode 100644 omni_python_sdk/models/connections_update_connections_update_body.py create mode 100644 omni_python_sdk/models/connections_update_connections_update_body_environment_user_attribute_type_0.py create mode 100644 omni_python_sdk/models/connections_update_connections_update_response.py create mode 100644 omni_python_sdk/models/containers_item.py create mode 100644 omni_python_sdk/models/content_filter_mode.py create mode 100644 omni_python_sdk/models/content_list_response.py create mode 100644 omni_python_sdk/models/content_list_response_records_item_type_0.py create mode 100644 omni_python_sdk/models/content_list_response_records_item_type_0_type.py create mode 100644 omni_python_sdk/models/content_list_response_records_item_type_1.py create mode 100644 omni_python_sdk/models/content_list_response_records_item_type_1_count.py create mode 100644 omni_python_sdk/models/content_list_response_records_item_type_1_owner.py create mode 100644 omni_python_sdk/models/content_list_response_records_item_type_1_scope.py create mode 100644 omni_python_sdk/models/content_list_response_records_item_type_1_type.py create mode 100644 omni_python_sdk/models/content_list_scope.py create mode 100644 omni_python_sdk/models/content_list_sort_direction.py create mode 100644 omni_python_sdk/models/content_list_sort_field.py create mode 100644 omni_python_sdk/models/content_share_scope.py create mode 100644 omni_python_sdk/models/control_patch_external.py create mode 100644 omni_python_sdk/models/control_read_external.py create mode 100644 omni_python_sdk/models/controls_patch_external.py create mode 100644 omni_python_sdk/models/controls_read_external.py create mode 100644 omni_python_sdk/models/create_model_schema_base.py create mode 100644 omni_python_sdk/models/create_model_schema_base_access_grants_item.py create mode 100644 omni_python_sdk/models/create_model_schema_base_access_grants_item_code_comments.py create mode 100644 omni_python_sdk/models/create_model_schema_base_model_kind_type_0.py create mode 100644 omni_python_sdk/models/create_model_schema_base_model_kind_type_1.py create mode 100644 omni_python_sdk/models/create_model_schema_base_model_kind_type_2.py create mode 100644 omni_python_sdk/models/create_model_schema_base_model_kind_type_3.py create mode 100644 omni_python_sdk/models/dashboard_filters_response.py create mode 100644 omni_python_sdk/models/dashboards_download_body.py create mode 100644 omni_python_sdk/models/dashboards_download_body_format.py create mode 100644 omni_python_sdk/models/dashboards_download_body_paper_format.py create mode 100644 omni_python_sdk/models/dashboards_download_body_paper_orientation.py create mode 100644 omni_python_sdk/models/dashboards_download_response.py create mode 100644 omni_python_sdk/models/dashboards_update_filters_body.py create mode 100644 omni_python_sdk/models/dashboards_update_filters_body_controls.py create mode 100644 omni_python_sdk/models/dashboards_update_filters_body_controls_additional_property.py create mode 100644 omni_python_sdk/models/dashboards_update_filters_body_filters.py create mode 100644 omni_python_sdk/models/dashboards_update_filters_body_filters_additional_property.py create mode 100644 omni_python_sdk/models/dbt_environment_create_body.py create mode 100644 omni_python_sdk/models/dbt_environment_delete_response.py create mode 100644 omni_python_sdk/models/dbt_environment_item.py create mode 100644 omni_python_sdk/models/dbt_environment_list_response.py create mode 100644 omni_python_sdk/models/dbt_environment_response_variable.py create mode 100644 omni_python_sdk/models/dbt_environment_update_body.py create mode 100644 omni_python_sdk/models/dbt_environment_variable.py create mode 100644 omni_python_sdk/models/dbt_environment_variable_update.py create mode 100644 omni_python_sdk/models/dbt_exposure.py create mode 100644 omni_python_sdk/models/dbt_exposure_owner.py create mode 100644 omni_python_sdk/models/dbt_exposure_type.py create mode 100644 omni_python_sdk/models/dbt_exposure_with_meta.py create mode 100644 omni_python_sdk/models/document.py create mode 100644 omni_python_sdk/models/document_count.py create mode 100644 omni_python_sdk/models/document_export_response.py create mode 100644 omni_python_sdk/models/document_export_response_document.py create mode 100644 omni_python_sdk/models/document_export_response_file_uploads.py create mode 100644 omni_python_sdk/models/document_export_response_query_models.py create mode 100644 omni_python_sdk/models/document_favorite_user.py create mode 100644 omni_python_sdk/models/document_folder_type_0.py create mode 100644 omni_python_sdk/models/document_folder_type_0_scope.py create mode 100644 omni_python_sdk/models/document_import_body.py create mode 100644 omni_python_sdk/models/document_import_body_document.py create mode 100644 omni_python_sdk/models/document_import_body_export_version.py create mode 100644 omni_python_sdk/models/document_import_body_file_uploads.py create mode 100644 omni_python_sdk/models/document_import_body_query_models.py create mode 100644 omni_python_sdk/models/document_import_response.py create mode 100644 omni_python_sdk/models/document_owner.py create mode 100644 omni_python_sdk/models/document_scope.py create mode 100644 omni_python_sdk/models/document_type.py create mode 100644 omni_python_sdk/models/documents_access_list_access_source.py create mode 100644 omni_python_sdk/models/documents_access_list_response.py create mode 100644 omni_python_sdk/models/documents_access_list_sort_direction.py create mode 100644 omni_python_sdk/models/documents_access_list_type.py create mode 100644 omni_python_sdk/models/documents_add_permits_body.py create mode 100644 omni_python_sdk/models/documents_add_permits_body_role.py create mode 100644 omni_python_sdk/models/documents_bulk_update_labels_body.py create mode 100644 omni_python_sdk/models/documents_bulk_update_labels_response.py create mode 100644 omni_python_sdk/models/documents_create_body.py create mode 100644 omni_python_sdk/models/documents_create_body_query_presentations_item.py create mode 100644 omni_python_sdk/models/documents_create_body_query_presentations_item_query.py create mode 100644 omni_python_sdk/models/documents_create_draft_body.py create mode 100644 omni_python_sdk/models/documents_create_draft_response.py create mode 100644 omni_python_sdk/models/documents_create_response.py create mode 100644 omni_python_sdk/models/documents_create_response_dashboard.py create mode 100644 omni_python_sdk/models/documents_create_response_workbook.py create mode 100644 omni_python_sdk/models/documents_discard_draft_body.py create mode 100644 omni_python_sdk/models/documents_discard_draft_response.py create mode 100644 omni_python_sdk/models/documents_duplicate_body.py create mode 100644 omni_python_sdk/models/documents_duplicate_body_scope.py create mode 100644 omni_python_sdk/models/documents_duplicate_response.py create mode 100644 omni_python_sdk/models/documents_get_permissions_response.py create mode 100644 omni_python_sdk/models/documents_get_queries_response.py create mode 100644 omni_python_sdk/models/documents_get_queries_response_queries_item.py create mode 100644 omni_python_sdk/models/documents_get_response.py create mode 100644 omni_python_sdk/models/documents_list_favorites_response.py create mode 100644 omni_python_sdk/models/documents_list_favorites_sort_direction.py create mode 100644 omni_python_sdk/models/documents_list_response.py create mode 100644 omni_python_sdk/models/documents_list_sort_direction.py create mode 100644 omni_python_sdk/models/documents_list_sort_field.py create mode 100644 omni_python_sdk/models/documents_move_body.py create mode 100644 omni_python_sdk/models/documents_move_body_scope.py create mode 100644 omni_python_sdk/models/documents_put_body.py create mode 100644 omni_python_sdk/models/documents_put_query_presentation.py create mode 100644 omni_python_sdk/models/documents_put_query_presentation_ai_config.py create mode 100644 omni_python_sdk/models/documents_put_query_presentation_ai_config_description.py create mode 100644 omni_python_sdk/models/documents_put_query_presentation_ai_config_sub_title.py create mode 100644 omni_python_sdk/models/documents_put_query_presentation_chart_type_type_1.py create mode 100644 omni_python_sdk/models/documents_put_query_presentation_chart_type_type_2_type_1.py create mode 100644 omni_python_sdk/models/documents_put_query_presentation_chart_type_type_3_type_1.py create mode 100644 omni_python_sdk/models/documents_put_response.py create mode 100644 omni_python_sdk/models/documents_revoke_permits_body.py create mode 100644 omni_python_sdk/models/documents_transfer_ownership_body.py create mode 100644 omni_python_sdk/models/documents_update_body.py create mode 100644 omni_python_sdk/models/documents_update_permission_settings_body.py create mode 100644 omni_python_sdk/models/documents_update_permission_settings_body_organization_role.py create mode 100644 omni_python_sdk/models/documents_update_permits_body.py create mode 100644 omni_python_sdk/models/documents_update_permits_body_role.py create mode 100644 omni_python_sdk/models/documents_update_response.py create mode 100644 omni_python_sdk/models/documents_upgrade_layout_body.py create mode 100644 omni_python_sdk/models/documents_upgrade_layout_response.py create mode 100644 omni_python_sdk/models/documents_v2_create_body.py create mode 100644 omni_python_sdk/models/documents_v2_create_draft_body.py create mode 100644 omni_python_sdk/models/documents_v2_create_response.py create mode 100644 omni_python_sdk/models/documents_v2_get_draft_pretty.py create mode 100644 omni_python_sdk/models/documents_v2_get_pretty.py create mode 100644 omni_python_sdk/models/documents_v2_patch_draft_body.py create mode 100644 omni_python_sdk/models/documents_v2_patch_draft_response.py create mode 100644 omni_python_sdk/models/documents_v2_publish_draft_response.py create mode 100644 omni_python_sdk/models/documents_v2_read_response.py create mode 100644 omni_python_sdk/models/documents_v2_update_identifier_body.py create mode 100644 omni_python_sdk/models/documents_v2_update_identifier_response.py create mode 100644 omni_python_sdk/models/email_recipient.py create mode 100644 omni_python_sdk/models/embed_sso_generate_session_body.py create mode 100644 omni_python_sdk/models/embed_sso_generate_session_body_user_attributes.py create mode 100644 omni_python_sdk/models/embed_sso_generate_session_response.py create mode 100644 omni_python_sdk/models/eval_api_error_400.py create mode 100644 omni_python_sdk/models/eval_api_error_401.py create mode 100644 omni_python_sdk/models/eval_api_error_403.py create mode 100644 omni_python_sdk/models/eval_api_error_404.py create mode 100644 omni_python_sdk/models/eval_api_error_422.py create mode 100644 omni_python_sdk/models/eval_api_error_429.py create mode 100644 omni_python_sdk/models/eval_api_error_500.py create mode 100644 omni_python_sdk/models/eval_api_error_503.py create mode 100644 omni_python_sdk/models/eval_prompt.py create mode 100644 omni_python_sdk/models/eval_prompt_set.py create mode 100644 omni_python_sdk/models/eval_prompt_set_list_item.py create mode 100644 omni_python_sdk/models/eval_prompt_sets_create_body.py create mode 100644 omni_python_sdk/models/eval_prompt_sets_create_body_prompts_item.py create mode 100644 omni_python_sdk/models/eval_prompt_sets_create_response.py create mode 100644 omni_python_sdk/models/eval_prompt_sets_delete_response.py create mode 100644 omni_python_sdk/models/eval_prompt_sets_get_response.py create mode 100644 omni_python_sdk/models/eval_prompt_sets_list_response.py create mode 100644 omni_python_sdk/models/eval_prompt_sets_unarchive_response.py create mode 100644 omni_python_sdk/models/eval_prompt_sets_update_body.py create mode 100644 omni_python_sdk/models/eval_prompt_sets_update_body_prompts_item.py create mode 100644 omni_python_sdk/models/eval_prompt_sets_update_response.py create mode 100644 omni_python_sdk/models/eval_run_detail.py create mode 100644 omni_python_sdk/models/eval_run_detail_status.py create mode 100644 omni_python_sdk/models/eval_run_list_item.py create mode 100644 omni_python_sdk/models/eval_run_list_item_status.py create mode 100644 omni_python_sdk/models/eval_run_result.py create mode 100644 omni_python_sdk/models/eval_run_result_agentic_job.py create mode 100644 omni_python_sdk/models/eval_run_result_agentic_job_state.py create mode 100644 omni_python_sdk/models/eval_run_stats.py create mode 100644 omni_python_sdk/models/eval_runs_cancel_response.py create mode 100644 omni_python_sdk/models/eval_runs_create_body.py create mode 100644 omni_python_sdk/models/eval_runs_create_body_run_config.py create mode 100644 omni_python_sdk/models/eval_runs_create_response.py create mode 100644 omni_python_sdk/models/eval_runs_delete_response.py create mode 100644 omni_python_sdk/models/eval_runs_get_response.py create mode 100644 omni_python_sdk/models/eval_runs_list_response.py create mode 100644 omni_python_sdk/models/eval_runs_unarchive_response.py create mode 100644 omni_python_sdk/models/folders_add_permissions_body.py create mode 100644 omni_python_sdk/models/folders_add_permissions_body_role.py create mode 100644 omni_python_sdk/models/folders_add_permissions_response.py create mode 100644 omni_python_sdk/models/folders_create_body.py create mode 100644 omni_python_sdk/models/folders_create_body_scope.py create mode 100644 omni_python_sdk/models/folders_create_response.py create mode 100644 omni_python_sdk/models/folders_create_response_scope.py create mode 100644 omni_python_sdk/models/folders_delete_response.py create mode 100644 omni_python_sdk/models/folders_get_permissions_response.py create mode 100644 omni_python_sdk/models/folders_get_permissions_response_permits_item.py create mode 100644 omni_python_sdk/models/folders_list_response.py create mode 100644 omni_python_sdk/models/folders_list_response_records_item.py create mode 100644 omni_python_sdk/models/folders_list_response_records_item_count.py create mode 100644 omni_python_sdk/models/folders_list_scope.py create mode 100644 omni_python_sdk/models/folders_list_sort_direction.py create mode 100644 omni_python_sdk/models/folders_list_sort_field.py create mode 100644 omni_python_sdk/models/folders_revoke_permissions_body.py create mode 100644 omni_python_sdk/models/folders_revoke_permissions_response.py create mode 100644 omni_python_sdk/models/folders_update_body.py create mode 100644 omni_python_sdk/models/folders_update_permissions_body.py create mode 100644 omni_python_sdk/models/folders_update_permissions_body_role.py create mode 100644 omni_python_sdk/models/folders_update_permissions_response.py create mode 100644 omni_python_sdk/models/folders_update_response.py create mode 100644 omni_python_sdk/models/grid_container.py create mode 100644 omni_python_sdk/models/ignore_suggestion_body.py create mode 100644 omni_python_sdk/models/internal_folder_type_0.py create mode 100644 omni_python_sdk/models/job_created_response.py create mode 100644 omni_python_sdk/models/jobs_get_status_response.py create mode 100644 omni_python_sdk/models/jobs_get_status_response_status.py create mode 100644 omni_python_sdk/models/json_value.py create mode 100644 omni_python_sdk/models/labels_create_body.py create mode 100644 omni_python_sdk/models/labels_create_response.py create mode 100644 omni_python_sdk/models/labels_get_response.py create mode 100644 omni_python_sdk/models/labels_list_response.py create mode 100644 omni_python_sdk/models/labels_list_response_labels_item.py create mode 100644 omni_python_sdk/models/labels_update_body.py create mode 100644 omni_python_sdk/models/labels_update_response.py create mode 100644 omni_python_sdk/models/model_suggestion.py create mode 100644 omni_python_sdk/models/model_suggestions_list_response.py create mode 100644 omni_python_sdk/models/model_suggestions_list_status.py create mode 100644 omni_python_sdk/models/model_yaml_create_request_body.py create mode 100644 omni_python_sdk/models/model_yaml_create_request_body_mode.py create mode 100644 omni_python_sdk/models/model_yaml_response.py create mode 100644 omni_python_sdk/models/model_yaml_response_checksums.py create mode 100644 omni_python_sdk/models/model_yaml_response_files.py create mode 100644 omni_python_sdk/models/model_yaml_response_view_names.py create mode 100644 omni_python_sdk/models/models_branch_dbt_body.py create mode 100644 omni_python_sdk/models/models_cache_reset_body.py create mode 100644 omni_python_sdk/models/models_cache_reset_response.py create mode 100644 omni_python_sdk/models/models_cache_reset_response_cache_reset.py create mode 100644 omni_python_sdk/models/models_commit_body.py create mode 100644 omni_python_sdk/models/models_commit_response.py create mode 100644 omni_python_sdk/models/models_content_validator_get_find_type.py create mode 100644 omni_python_sdk/models/models_content_validator_get_response.py create mode 100644 omni_python_sdk/models/models_content_validator_get_response_branch_type_0.py create mode 100644 omni_python_sdk/models/models_content_validator_replace_body.py create mode 100644 omni_python_sdk/models/models_content_validator_replace_body_find_or_replace_type.py create mode 100644 omni_python_sdk/models/models_content_validator_replace_response.py create mode 100644 omni_python_sdk/models/models_create_field_body.py create mode 100644 omni_python_sdk/models/models_create_field_body_aggregate_type.py create mode 100644 omni_python_sdk/models/models_create_models_create_response.py create mode 100644 omni_python_sdk/models/models_create_models_create_response_model.py create mode 100644 omni_python_sdk/models/models_dbt_exposures_response.py create mode 100644 omni_python_sdk/models/models_dbt_exposures_sort_direction.py create mode 100644 omni_python_sdk/models/models_delete_topic_mode.py create mode 100644 omni_python_sdk/models/models_delete_view_mode.py create mode 100644 omni_python_sdk/models/models_get_schemas_response.py create mode 100644 omni_python_sdk/models/models_get_topic_response.py create mode 100644 omni_python_sdk/models/models_get_topic_response_topic.py create mode 100644 omni_python_sdk/models/models_get_topic_response_topic_relationships_item.py create mode 100644 omni_python_sdk/models/models_get_topic_response_topic_views_item.py create mode 100644 omni_python_sdk/models/models_get_view_response.py create mode 100644 omni_python_sdk/models/models_get_view_response_views_item.py create mode 100644 omni_python_sdk/models/models_get_view_response_views_item_fields_item.py create mode 100644 omni_python_sdk/models/models_get_view_response_views_item_fields_item_type.py create mode 100644 omni_python_sdk/models/models_git_create_body.py create mode 100644 omni_python_sdk/models/models_git_create_body_auth_method.py create mode 100644 omni_python_sdk/models/models_git_create_body_git_service_provider.py create mode 100644 omni_python_sdk/models/models_git_create_body_require_pull_request.py create mode 100644 omni_python_sdk/models/models_git_create_response.py create mode 100644 omni_python_sdk/models/models_git_create_response_auth_method.py create mode 100644 omni_python_sdk/models/models_git_create_response_require_pull_request.py create mode 100644 omni_python_sdk/models/models_git_delete_response.py create mode 100644 omni_python_sdk/models/models_git_get_response.py create mode 100644 omni_python_sdk/models/models_git_get_response_auth_method.py create mode 100644 omni_python_sdk/models/models_git_get_response_require_pull_request.py create mode 100644 omni_python_sdk/models/models_git_sync_body.py create mode 100644 omni_python_sdk/models/models_git_sync_response.py create mode 100644 omni_python_sdk/models/models_git_update_body.py create mode 100644 omni_python_sdk/models/models_git_update_body_auth_method.py create mode 100644 omni_python_sdk/models/models_git_update_body_git_service_provider.py create mode 100644 omni_python_sdk/models/models_git_update_body_require_pull_request.py create mode 100644 omni_python_sdk/models/models_git_update_response.py create mode 100644 omni_python_sdk/models/models_git_update_response_auth_method.py create mode 100644 omni_python_sdk/models/models_git_update_response_require_pull_request.py create mode 100644 omni_python_sdk/models/models_list_include_deleted.py create mode 100644 omni_python_sdk/models/models_list_model_kind.py create mode 100644 omni_python_sdk/models/models_list_response.py create mode 100644 omni_python_sdk/models/models_list_response_records_item.py create mode 100644 omni_python_sdk/models/models_list_response_records_item_branches_item.py create mode 100644 omni_python_sdk/models/models_list_sort_direction.py create mode 100644 omni_python_sdk/models/models_list_sort_field.py create mode 100644 omni_python_sdk/models/models_list_topics_response.py create mode 100644 omni_python_sdk/models/models_list_topics_response_topics_item.py create mode 100644 omni_python_sdk/models/models_merge_branch_body.py create mode 100644 omni_python_sdk/models/models_merge_branch_response.py create mode 100644 omni_python_sdk/models/models_migrate_body.py create mode 100644 omni_python_sdk/models/models_refresh_hard_refresh.py create mode 100644 omni_python_sdk/models/models_refresh_response.py create mode 100644 omni_python_sdk/models/models_refresh_response_status.py create mode 100644 omni_python_sdk/models/models_update_body.py create mode 100644 omni_python_sdk/models/models_update_field_body.py create mode 100644 omni_python_sdk/models/models_update_field_body_filters.py create mode 100644 omni_python_sdk/models/models_update_field_body_group_filters_item.py create mode 100644 omni_python_sdk/models/models_update_response.py create mode 100644 omni_python_sdk/models/models_update_response_model.py create mode 100644 omni_python_sdk/models/models_update_topic_body.py create mode 100644 omni_python_sdk/models/models_update_view_body.py create mode 100644 omni_python_sdk/models/models_validate_response.py create mode 100644 omni_python_sdk/models/models_validate_response_issues_item.py create mode 100644 omni_python_sdk/models/models_validate_response_issues_item_severity.py create mode 100644 omni_python_sdk/models/models_yaml_delete_mode.py create mode 100644 omni_python_sdk/models/models_yaml_get_mode.py create mode 100644 omni_python_sdk/models/owner_internal.py create mode 100644 omni_python_sdk/models/page_container.py create mode 100644 omni_python_sdk/models/page_info.py create mode 100644 omni_python_sdk/models/query_presentation_patch_external.py create mode 100644 omni_python_sdk/models/query_presentation_read_external.py create mode 100644 omni_python_sdk/models/query_presentations_patch_external.py create mode 100644 omni_python_sdk/models/query_presentations_read_external.py create mode 100644 omni_python_sdk/models/query_run_body.py create mode 100644 omni_python_sdk/models/query_run_body_cache.py create mode 100644 omni_python_sdk/models/query_run_body_result_type.py create mode 100644 omni_python_sdk/models/query_run_response.py create mode 100644 omni_python_sdk/models/query_timeout_response.py create mode 100644 omni_python_sdk/models/query_wait_response.py create mode 100644 omni_python_sdk/models/reference_container.py create mode 100644 omni_python_sdk/models/role_assignment_result.py create mode 100644 omni_python_sdk/models/role_origin_type_0.py create mode 100644 omni_python_sdk/models/role_origin_type_0_type.py create mode 100644 omni_python_sdk/models/role_origin_type_1.py create mode 100644 omni_python_sdk/models/role_origin_type_1_type.py create mode 100644 omni_python_sdk/models/role_origin_type_2.py create mode 100644 omni_python_sdk/models/role_origin_type_2_type.py create mode 100644 omni_python_sdk/models/role_origin_type_3.py create mode 100644 omni_python_sdk/models/role_origin_type_3_type.py create mode 100644 omni_python_sdk/models/routine_create_body.py create mode 100644 omni_python_sdk/models/routine_create_response.py create mode 100644 omni_python_sdk/models/routine_delete_response.py create mode 100644 omni_python_sdk/models/routine_email_destination.py create mode 100644 omni_python_sdk/models/routine_email_destination_response.py create mode 100644 omni_python_sdk/models/routine_email_destination_response_type.py create mode 100644 omni_python_sdk/models/routine_email_destination_type.py create mode 100644 omni_python_sdk/models/routine_last_run_type_0.py create mode 100644 omni_python_sdk/models/routine_response.py create mode 100644 omni_python_sdk/models/routine_slack_destination.py create mode 100644 omni_python_sdk/models/routine_slack_destination_slack_recipient_type.py create mode 100644 omni_python_sdk/models/routine_slack_destination_type.py create mode 100644 omni_python_sdk/models/routine_trigger_response.py create mode 100644 omni_python_sdk/models/routine_update_body.py create mode 100644 omni_python_sdk/models/routines_list_response.py create mode 100644 omni_python_sdk/models/routines_list_sort_direction.py create mode 100644 omni_python_sdk/models/schedule_suggestions_body.py create mode 100644 omni_python_sdk/models/schedule_suggestions_response.py create mode 100644 omni_python_sdk/models/schedule_suggestions_response_status.py create mode 100644 omni_python_sdk/models/schedules_add_recipients_body.py create mode 100644 omni_python_sdk/models/schedules_add_recipients_response.py create mode 100644 omni_python_sdk/models/schedules_create_schedules_create_body.py create mode 100644 omni_python_sdk/models/schedules_create_schedules_create_body_condition_type.py create mode 100644 omni_python_sdk/models/schedules_create_schedules_create_body_destination_type.py create mode 100644 omni_python_sdk/models/schedules_create_schedules_create_body_format.py create mode 100644 omni_python_sdk/models/schedules_create_schedules_create_body_recipients_item.py create mode 100644 omni_python_sdk/models/schedules_create_schedules_create_response.py create mode 100644 omni_python_sdk/models/schedules_get_destination.py create mode 100644 omni_python_sdk/models/schedules_get_recipient.py create mode 100644 omni_python_sdk/models/schedules_get_recipient_membership.py create mode 100644 omni_python_sdk/models/schedules_get_recipient_membership_user.py create mode 100644 omni_python_sdk/models/schedules_get_response.py create mode 100644 omni_python_sdk/models/schedules_get_response_owner.py create mode 100644 omni_python_sdk/models/schedules_list_content_type.py create mode 100644 omni_python_sdk/models/schedules_list_destination.py create mode 100644 omni_python_sdk/models/schedules_list_item.py create mode 100644 omni_python_sdk/models/schedules_list_item_alert.py create mode 100644 omni_python_sdk/models/schedules_list_response_200.py create mode 100644 omni_python_sdk/models/schedules_list_schedule_type.py create mode 100644 omni_python_sdk/models/schedules_list_sort_direction.py create mode 100644 omni_python_sdk/models/schedules_list_sort_field.py create mode 100644 omni_python_sdk/models/schedules_list_status.py create mode 100644 omni_python_sdk/models/schedules_recipients_get_response.py create mode 100644 omni_python_sdk/models/schedules_recipients_get_response_type.py create mode 100644 omni_python_sdk/models/schedules_remove_recipients_body.py create mode 100644 omni_python_sdk/models/schedules_remove_recipients_response.py create mode 100644 omni_python_sdk/models/schedules_transfer_ownership_body.py create mode 100644 omni_python_sdk/models/scim_group_response.py create mode 100644 omni_python_sdk/models/scim_group_response_members_item.py create mode 100644 omni_python_sdk/models/scim_groups_create_body.py create mode 100644 omni_python_sdk/models/scim_groups_create_body_members_item.py create mode 100644 omni_python_sdk/models/scim_groups_get_excluded_attributes.py create mode 100644 omni_python_sdk/models/scim_groups_list_excluded_attributes.py create mode 100644 omni_python_sdk/models/scim_groups_list_response.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_0.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_0_op.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_0_value.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_1.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_1_op.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_op.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_path.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_value_item.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3_op.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3_path.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3_value_type_0_item.py create mode 100644 omni_python_sdk/models/scim_groups_patch_body_schemas_item.py create mode 100644 omni_python_sdk/models/scim_groups_replace_body.py create mode 100644 omni_python_sdk/models/scim_groups_replace_body_members_item.py create mode 100644 omni_python_sdk/models/scim_user_create_request.py create mode 100644 omni_python_sdk/models/scim_user_create_request_urnomniparams_10_user_attribute.py create mode 100644 omni_python_sdk/models/scim_user_create_request_urnomniparams_10_user_attribute_additional_property_type_6.py create mode 100644 omni_python_sdk/models/scim_user_patch_request.py create mode 100644 omni_python_sdk/models/scim_user_patch_request_operations_item.py create mode 100644 omni_python_sdk/models/scim_user_patch_request_operations_item_op.py create mode 100644 omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6.py create mode 100644 omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user.py create mode 100644 omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6.py create mode 100644 omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute.py create mode 100644 omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute_additional_property_type_6.py create mode 100644 omni_python_sdk/models/scim_user_patch_request_schemas_item.py create mode 100644 omni_python_sdk/models/scim_user_put_request.py create mode 100644 omni_python_sdk/models/scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user.py create mode 100644 omni_python_sdk/models/scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6.py create mode 100644 omni_python_sdk/models/scim_user_put_request_urnomniparams_10_user_attribute.py create mode 100644 omni_python_sdk/models/scim_user_put_request_urnomniparams_10_user_attribute_additional_property_type_6.py create mode 100644 omni_python_sdk/models/scim_user_response.py create mode 100644 omni_python_sdk/models/scim_users_list_response.py create mode 100644 omni_python_sdk/models/settings_patch_external.py create mode 100644 omni_python_sdk/models/settings_patch_external_custom_text_type_0.py create mode 100644 omni_python_sdk/models/settings_patch_external_run_queries_on_type_1.py create mode 100644 omni_python_sdk/models/settings_patch_external_run_queries_on_type_2_type_1.py create mode 100644 omni_python_sdk/models/settings_patch_external_run_queries_on_type_3_type_1.py create mode 100644 omni_python_sdk/models/settings_read_external.py create mode 100644 omni_python_sdk/models/settings_read_external_custom_text_type_0.py create mode 100644 omni_python_sdk/models/settings_read_external_run_queries_on_type_1.py create mode 100644 omni_python_sdk/models/settings_read_external_run_queries_on_type_2_type_1.py create mode 100644 omni_python_sdk/models/settings_read_external_run_queries_on_type_3_type_1.py create mode 100644 omni_python_sdk/models/stack_container.py create mode 100644 omni_python_sdk/models/success_response.py create mode 100644 omni_python_sdk/models/suggestion_context_edit.py create mode 100644 omni_python_sdk/models/suggestion_evidence_item.py create mode 100644 omni_python_sdk/models/suggestion_evidence_item_type.py create mode 100644 omni_python_sdk/models/suggestion_proposed_changes.py create mode 100644 omni_python_sdk/models/suggestion_proposed_changes_kind.py create mode 100644 omni_python_sdk/models/upload.py create mode 100644 omni_python_sdk/models/upload_create_body.py create mode 100644 omni_python_sdk/models/upload_create_response.py create mode 100644 omni_python_sdk/models/upload_delete_response.py create mode 100644 omni_python_sdk/models/upload_uploaded_by_user_type_0.py create mode 100644 omni_python_sdk/models/uploads_list_response.py create mode 100644 omni_python_sdk/models/uploads_list_sort_direction.py create mode 100644 omni_python_sdk/models/uploads_list_sort_field.py create mode 100644 omni_python_sdk/models/uploads_list_type.py create mode 100644 omni_python_sdk/models/user_attributes_list_response.py create mode 100644 omni_python_sdk/models/user_attributes_list_response_records_item.py create mode 100644 omni_python_sdk/models/user_attributes_list_response_records_item_type.py create mode 100644 omni_python_sdk/models/user_group_recipient.py create mode 100644 omni_python_sdk/models/user_group_role_assignment_result.py create mode 100644 omni_python_sdk/models/user_group_role_origin.py create mode 100644 omni_python_sdk/models/user_group_role_origin_type.py create mode 100644 omni_python_sdk/models/user_groups_assign_model_role_body.py create mode 100644 omni_python_sdk/models/user_groups_assign_model_role_response.py create mode 100644 omni_python_sdk/models/user_groups_get_model_roles_response.py create mode 100644 omni_python_sdk/models/users_assign_model_role_body.py create mode 100644 omni_python_sdk/models/users_assign_model_role_response.py create mode 100644 omni_python_sdk/models/users_create_email_only_body.py create mode 100644 omni_python_sdk/models/users_create_email_only_body_user_attributes.py create mode 100644 omni_python_sdk/models/users_create_email_only_bulk_body.py create mode 100644 omni_python_sdk/models/users_create_email_only_bulk_body_users_item.py create mode 100644 omni_python_sdk/models/users_create_email_only_bulk_body_users_item_user_attributes.py create mode 100644 omni_python_sdk/models/users_create_email_only_bulk_response.py create mode 100644 omni_python_sdk/models/users_create_email_only_bulk_response_results_item.py create mode 100644 omni_python_sdk/models/users_create_email_only_response.py create mode 100644 omni_python_sdk/models/users_get_model_roles_response.py create mode 100644 omni_python_sdk/models/users_list_email_only_response.py create mode 100644 omni_python_sdk/models/users_list_email_only_response_records_item.py create mode 100644 omni_python_sdk/models/users_list_email_only_response_records_item_user_attributes.py create mode 100644 omni_python_sdk/models/users_list_email_only_sort_direction.py create mode 100644 omni_python_sdk/models/whoami_model_role.py create mode 100644 omni_python_sdk/models/whoami_model_role_permissions_item.py create mode 100644 omni_python_sdk/models/whoami_response.py create mode 100644 omni_python_sdk/models/whoami_response_key_scope.py create mode 100644 omni_python_sdk/models/whoami_response_org_role.py create mode 100644 omni_python_sdk/models/whoami_response_roles_by_model.py create mode 100644 omni_python_sdk/models/whoami_user.py create mode 100644 omni_python_sdk/py.typed create mode 100644 omni_python_sdk/types.py diff --git a/omni_python_sdk/__init__.py b/omni_python_sdk/__init__.py index 5c07b62..61fc1ff 100644 --- a/omni_python_sdk/__init__.py +++ b/omni_python_sdk/__init__.py @@ -1,3 +1,8 @@ -from .api import OmniAPI +"""A client library for accessing Omni API""" -__all__ = ['OmniAPI'] +from .client import AuthenticatedClient, Client + +__all__ = ( + "AuthenticatedClient", + "Client", +) diff --git a/omni_python_sdk/api.py b/omni_python_sdk/api.py deleted file mode 100644 index 1b37d90..0000000 --- a/omni_python_sdk/api.py +++ /dev/null @@ -1,779 +0,0 @@ -import os -from dotenv import load_dotenv -import requests -import urllib.parse -import pyarrow as pa -import pyarrow.ipc as ipc -import io -import json, ndjson, base64 -from typing import List, Tuple, Any, Union -import functools, collections - - -def requests_error_handler(func): - """ - Decorator to handle generic errors when raising a status - via `response.raise_for_status()`. It catches all exceptions that occur when - calling the decorated function and prints an error message with exception details. - Args: - func (callable): The function to be decorated. - Returns: - wrapper (callable): A wrapper function that handles exceptions. - Raises: - None (handled internally) - Example Use: - @requests_error_handler - def get_data(url): - response = requests.get(url) - response.raise_for_status() - return response.json() - """ - @functools.wraps(func) - def wrapper(*args, **kwargs): - try: - return func(*args, **kwargs) - except Exception as e: - print(f"Request Failed: {e}") - return None - return wrapper - -class memoized(object): - '''Decorator. Caches a function's return value each time it is called. - If called later with the same arguments, the cached value is returned - (not reevaluated). - ''' - def __init__(self, func): - self.func = func - self.cache = {} - def __call__(self, *args): - if not isinstance(args, collections.abc.Hashable): - # uncacheable. a list, for instance. - # better to not cache than blow up. - return self.func(*args) - if args in self.cache: - return self.cache[args] - else: - value = self.func(*args) - self.cache[args] = value - return value - def __repr__(self): - '''Return the function's docstring.''' - return self.func.__doc__ - def __get__(self, obj, objtype): - '''Support instance methods.''' - return functools.partial(self.__call__, obj) - -class OmniAPI: - def __init__(self, api_key: str = '', base_url: str = '',env_file: str = '.env'): - - if api_key and base_url: - self.api_key = api_key - self.base_url = base_url - elif load_dotenv(dotenv_path=env_file): - if os.getenv('OMNI_API_KEY'): - self.api_key = os.getenv('OMNI_API_KEY') - else: - self.api_key = api_key - if os.getenv('OMNI_BASE_URL'): - self.base_url = os.getenv('OMNI_BASE_URL') - else: - self.base_url = base_url - else: - self.api_key = api_key - self.base_url = base_url - self._trim_base_url() - self.headers = { - 'Authorization': f'Bearer {self.api_key}', - 'Content-Type': 'application/json' - } - - def _trim_base_url(self) -> None: - ''' - Trims the base_url to remove any trailing slashes or api versions - since the versioning of an endpoint is managed by the SDK methods, - and varies between endpoints - ''' - if self.base_url.endswith('/'): - self.base_url = self.base_url[:-1] - if self.base_url.endswith('/api/v1'): - self.base_url = self.base_url[:-7] - if self.base_url.endswith('/api'): - self.base_url = self.base_url[:-4] - if self.base_url.endswith('/api/unstable'): - self.base_url = self.base_url[:-13] - - @requests_error_handler - def wait_query_blocking(self, remaining_job_ids: List[str], version:str='v1') -> Tuple[Any, bool]: - """ - Wait for query jobs to complete. - Args: - remaining_job_ids (List[str]): List of job IDs to wait for. - Returns: - Tuple[Any, bool]: A tuple containing the response JSON and a boolean indicating if the jobs are done. - Raises: - requests.exceptions.RequestException: If the API request fails. - """ - ''' - remaining_job_ids: List[str] - the list of job ids to wait for - Wait for a query to complete by providing a list of job ids. - ''' - url = f"{self.base_url}/api/{version}/query/wait" - - # URL encode the query parameter - encoded_query = urllib.parse.urlencode({'job_ids': json.dumps(remaining_job_ids)}) - response = requests.get(f"{url}?{encoded_query}", headers=self.headers) - - if response.status_code == 200: - # Parse NDJSON response - response_json = ndjson.loads(response.text) - footer = response_json[-1] - done = footer['timed_out'] == 'false' - return response_json, done - else: - response.raise_for_status() - - @requests_error_handler - def run_query_blocking(self, body: dict, version:str='v1') -> Tuple[pa.Table, List[dict]]: - """ - Run a query and wait for its completion. - Args: - body (dict): The query body. - Returns: - Tuple[pa.Table, List[dict]]: A tuple containing the result table and field information. - Raises: - ValueError: If no result is found in the response. - requests.exceptions.RequestException: If the API request fails. - """ - url = f"{self.base_url}/api/{version}/query/run" - response = requests.post(url, headers=self.headers, json=body) - - if response.status_code == 200: - # Parse NDJSON response - response_json = ndjson.loads(response.text) - footer = response_json[-1] - done = footer['timed_out'] == 'false' - while not done: - response_json, done = self.wait_query_blocking(footer['remaining_job_ids']) - data_payload = next((data_payload for data_payload in response_json if "result" in data_payload), None) - if data_payload is not None: - base64_data = data_payload['result'] - raw_arrow_data = base64.b64decode(base64_data) - # Read Arrow table from raw data - buffer = io.BytesIO(raw_arrow_data) - reader = ipc.open_stream(buffer) - table = reader.read_all() - return table, data_payload['summary']['fields'] - else: - raise ValueError("No result found in the response.") - else: - response.raise_for_status() - - @requests_error_handler - def create_user(self, body: dict, version:str='v2') -> requests.Response: - """ - Create a new user. - Args: - body (dict): The user creation body. - Returns: - requests.Response: The response from the create operation. - Raises: - requests.exceptions.RequestException: If the API request fails. - """ - url = f"{self.base_url}/api/scim/{version}/users" - response = requests.post(url, headers=self.headers, json=body) - response.raise_for_status() - return response - - @requests_error_handler - def update_user(self, id: str, body: dict, version:str='v2') -> requests.Response: - """ - Update an existing user. - Args: - id (str): The ID of the user to update. - body (dict): The user update body. - Returns: - requests.Response: The response from the update operation. - Raises: - requests.exceptions.RequestException: If the API request fails. - """ - url = f"{self.base_url}/api/scim/{version}/users/{id}" - response = requests.put(url, headers=self.headers, json=body) - response.raise_for_status() - return response - - @requests_error_handler - def find_user_by_email(self, email: str, version:str='v2') -> requests.Response: - """ - Find a user by email. - Args: - email (str): The email of the user to find. - Returns: - requests.Response: The response containing the user information. - Raises: - requests.exceptions.RequestException: If the API request fails. - """ - url = f"{self.base_url}/api/scim/{version}/users" - response = requests.get(url, headers=self.headers, params={'filter': f'userName eq "{email}"'}) - response.raise_for_status() - return response - - def return_user_by_email(self, email: str) -> dict: - """ - Find a user by email and return object - Args: - email (str): The email of the user to find. - Returns: - dict: A dictionary containing the user's ID and display name. - Raises: - requests.exceptions.RequestException: If the API request fails. - """ - response = self.find_user_by_email(email) - if response.status_code == 200: - users = response.json()['Resources'] - if len(users) == 1: - return users[0] - else: - print(f"Found {len(users)} users for {email}") - return None - else: - print(f"Error finding user by email: {response.status_code}") - return None - - def upsert_user(self, email:str, displayName:str, attributes:dict, groups:List[str]=None): - """ - Create a new user or update an existing user's information. - Args: - email (str): The email address of the user. - displayName (str): The display name for the user. - attributes (dict): Additional attributes for the user. - Returns: - None - Prints: - Status messages about the operation's success or failure. - """ - body ={ - "urn:omni:params:1.0:UserAttribute":self.listify(attributes) - } - response = self.find_user_by_email(email) - if response.status_code == 200: - users = response.json()['Resources'] - if len(users) == 1: - user = users[0] - body.update({"userName":email, "displayName":displayName}) - update_response = self.update_user(user['id'],body) - if update_response.status_code == 200: - print(f"updated user id {user['id']}") - else: - print(f"Error ({update_response.status_code}) updating user id {user['id']}") - elif len(users) == 0: - body.update({"userName":email, "displayName":displayName}) - creation_response = self.create_user(body) - if creation_response.status_code == 201: - print(f'Created {email}, userid: {creation_response.json()["id"]}') - else: - print(f'Error creating {email}: {creation_response.status_code}') - - elif len(users) > 1: - print(f'{len(users)} found for {email}, no action taken') - - def delete_user(self, email): - """ - Delete a user by their email address. - Args: - email (str): The email address of the user to delete. - Returns: - requests.Response: The response object if the user is successfully deleted. - Prints: - Status messages about the operation's success or failure. - """ - users = self.find_user_by_email(email).json()['Resources'] - if len(users) == 1: - user = users[0] - response = self.delete_user_by_id(user['id']) - if response.status_code == 204: - print(f"deleted userid: {user['id']} email: {email}") - return response - elif len(users) > 1: - print('found too many users for email {email}: ') - for u in users: - print(u['id']) - elif len(users) == 0: - print(f'user {email} not found') - - @requests_error_handler - def delete_user_by_id(self, id:str, version:str='v2'): - """ - Delete a user by their user ID. - Args: - id (str): The ID of the user to delete. - Returns: - requests.Response: The response object from the delete operation. - """ - url = f"{self.base_url}/api/scim/{version}/users" - response = requests.delete(f"{url}/{id}", headers=self.headers) - response.raise_for_status() - return response - - @requests_error_handler - def document_export(self, id:str, version:str='unstable')->dict: - """ - Export a document by its ID. - Args: - id (str): The ID of the document to export. - Returns: - dict: The exported document data as a dictionary. - """ - url = f"{self.base_url}/api/{version}/documents/{id}/export" - response = requests.get(url,headers=self.headers) - response.raise_for_status() - return response.json() - - @requests_error_handler - def document_import(self, body:dict, version:str='unstable') -> requests.Response: - """ - Import a document. - Args: - body (dict): The document data to import. - Returns: - requests.Response: The response object from the import operation. - """ - url = f"{self.base_url}/api/{version}/documents/import" - response = requests.post(url,headers=self.headers, json=body) - response.raise_for_status() - return response - - @requests_error_handler - def list_folders(self, path:str='', version:str='v1') -> dict: - """ - List folders at the specified path. - Args: - path (str, optional): The path to list folders from. Defaults to an empty string. - Returns: - dict: A dictionary containing the list of folders. - """ - url = f"{self.base_url}/api/{version}/folders" - response = requests.get(url, - headers=self.headers, - params={ - 'path': path, - } - ) - response.raise_for_status() - return response.json() - - @requests_error_handler - def list_documents(self, folderId:str='', version:str='v1') -> dict: - """ - List documents in the specified folder. - Args: - folderId (str, optional): The ID of the folder to list documents from. Defaults to an empty string. - Returns: - dict: A dictionary containing the list of documents. - """ - url = f"{self.base_url}/api/{version}/documents" - response = requests.get(url, - headers=self.headers, - params={ - 'folderId': folderId if folderId else None, - } - ) - response.raise_for_status() - return response.json() - - @requests_error_handler - def list_groups(self, count:int=100,startIndex:int=1, version:str='v2') -> dict: - """ - List folders at the specified path. - Args: - count (int): The number of groups to return. Defaults to 100. - startIndex (int): An integer index that determines the starting point of the sorted result list. Defaults to 1. - Returns: - dict: A dictionary containing the list of folders. - """ - url = f"{self.base_url}/api/scim/{version}/groups" - response = requests.get(url, - headers=self.headers, - params={ - 'count': count, - 'startIndex': startIndex - } - ) - response.raise_for_status() - return response.json() - - @requests_error_handler - def generate_embed_url(self,body:dict) -> dict: - """ - Generate an embed URL. - Args: - body (dict): The request body containing necessary information for generating the embed URL. - Returns: - requests.Response: The response object containing the generated embed URL. - """ - url = f"{self.base_url}/embed/sso/generate-url" - response = requests.post(url, headers=self.headers, json=body) - response.raise_for_status() - return response - - @classmethod - def listify(cls, d:dict) -> dict: - """ - Convert string representations of lists in a dictionary to actual lists. - Args: - d (dict): The input dictionary. - Returns: - dict: A new dictionary with string representations of lists converted to actual lists. - """ - out = {} - for k,v in d.items(): - if '[' in v and ']' in v: - out.update({k:[item for item in v.replace('[','').replace(']','').split(',')]}) - else: - out.update({k:v}) - return out - - @memoized - def get_all_groups(self) -> List[dict]: - """ - Get all groups. - Returns: - List[dict]: A list of dictionaries containing group information. - """ - groups = [] - count = 100 - startIndex = 1 - while True: - response = self.list_groups(count, startIndex) - groups.extend(response['Resources']) - if response['totalResults'] <= startIndex: - break - startIndex += count - return groups - - @memoized - def get_group_id(self, group_name:str) -> Union[str,None]: - """ - Get the ID of a group by its name. - Args: - group_name (str): The name of the group to get the ID for. - Returns: - Union[str,None]: The ID of the group if found, otherwise None. - """ - groups = self.get_all_groups() - group = next((group for group in groups if group['displayName'] == group_name), None) - return group['id'] if group else None - - @requests_error_handler - def get_group(self, group_id:str, version:str='v2') -> dict: - """ - Get a group by its ID. - Args: - group_id (str): The ID of the group to get. - Returns: - dict: The group information. - """ - url = f"{self.base_url}/api/scim/{version}/groups/{group_id}" - response = requests.get(url, headers=self.headers) - response.raise_for_status() - return response.json() - - @requests_error_handler - def update_group(self, group_id:str, body:dict, version:str='v2') -> requests.Response: - """ - Update a group. - Args: - group_id (str): The ID of the group to update. - body (dict): The update body. - Returns: - requests.Response: The response object from the update operation. - """ - url = f"{self.base_url}/api/scim/{version}/groups/{group_id}" - response = requests.put(url, headers=self.headers, json=body) - response.raise_for_status() - return response - - @requests_error_handler - def add_user_to_group(self, group_name:str, user_id:str) -> requests.Response: - """ - Add a user to a group. - Args: - group_name (str): The name of the group to add the user to. - user_id (str): The ID of the user to add. - Returns: - requests.Response: The response object from the add operation. - """ - group_id = self.get_group_id(group_name) - if not group_id: - raise ValueError(f"Group '{group_name}' not found.") - group = self.get_group(group_id) - group['members'].append({ - "display": '', - "value": user_id - }) - return self.update_group(group_id, group) - - @requests_error_handler - def remove_user_from_group(self, group_name:str, user_id:str) -> requests.Response: - """ - Remove a user from a group. - Args: - group_name (str): The name of the group to remove the user from. - user_id (str): The ID of the user to remove. - Returns: - requests.Response: The response object from the remove operation. - """ - group_id = self.get_group_id(group_name) - if not group_id: - raise ValueError(f"Group '{group_name}' not found.") - group = self.get_group(group_id) - group['members'] = [member for member in group['members'] if member['value'] != user_id] - return self.update_group(group_id, group) - - @requests_error_handler - def create_model(self, connection_id: str, modelName:str, modelKind:str='SHARED', baseModelId:str=None, version:str='v1') -> dict: - """ - Create a new model. - Args: - connection_id (str): The connection ID. - body (dict): The model creation body. - Returns: - dict: The created model information. - Raises: - requests.exceptions.RequestException: If the API request fails. - """ - url = f"{self.base_url}/api/{version}/models" - body = {} - body["connectionId"] = connection_id - body["modelKind"] = modelKind - body["modelName"] = modelName - if baseModelId: - body["baseModelId"] = baseModelId - response = requests.post(url, headers=self.headers, json=body) - response.raise_for_status() - return response.json() - - @requests_error_handler - def list_models(self, connectionId:str='', baseModelId:str='', modelKind:str='', name:str='', version='v1') -> List[dict]: - """ - List models based on connection ID, base model ID, and model kind. - Args: - connectionId (str, optional): The connection ID to filter models. Defaults to an empty string. - baseModelId (str, optional): The base model ID to filter models. Defaults to an empty string. - modelKind (str, optional): The kind of model to filter models. Values can be: SCHEMA, SHARED, SHARED_EXTENSION, WORKBOOK, BRANCH, QUERY, TOPIC, FIELD_PICKER_TOPIC - version (str, optional): The API version to use. Defaults to 'v1'. - Returns: - List[dict]: A list of dictionaries containing model information. - Raises: - requests.exceptions.RequestException: If the API request fails. - """ - url = f"{self.base_url}/api/{version}/models" - response = requests.get(url, headers=self.headers, params={ - 'name': name if name else None, - 'connectionId': connectionId if connectionId else None, - 'baseModelId': baseModelId if baseModelId else None, - 'modelKind': modelKind if modelKind else None, - }) - response.raise_for_status() - return response.json() - - @requests_error_handler - def yamlw(self, model_id:str, body:dict, version='unstable') -> dict: - """ - Convert a dictionary to YAML format. - Args: - body (dict): The input dictionary to convert to YAML. - Returns: - dict: A dictionary containing the YAML representation of the input. - """ - url = f"{self.base_url}/api/{version}/models/{model_id}/yaml" - response = requests.post(url, headers=self.headers, json=body) - response.raise_for_status() - return response.json() - - @requests_error_handler - def yamlr(self, model_id:str, body:dict, version='unstable') -> dict: - """ - Convert a dictionary to YAML format. - Args: - body (dict): The k/v arguments supplied to the api - Returns: - dict: A dictionary containing the YAML representation of the input. - """ - url = f"{self.base_url}/api/{version}/models/{model_id}/yaml" - response = requests.get(url, headers=self.headers, params=body) - response.raise_for_status() - return response.json() - - def _base_model_url(self, version:str='v1') -> str: - """ - Get the base URL for model operations. - Returns: - str: The base URL for model operations. - """ - return f"{self.base_url}/api/{version}/model" - - def _model_url(self, model_id: str, version:str='v1') -> str: - """ - Get the URL for a specific model. - Args: - model_id (str): The ID of the model. - Returns: - str: The URL for the specified model. - """ - return f"{self._base_model_url(version)}/{model_id}" - - def _base_topic_url(self, model_id: str, version:str='v1') -> str: - """ - Get the base URL for topic operations. - Args: - model_id (str): The ID of the model. - Returns: - str: The base URL for topic operations. - """ - return f"{self._model_url(model_id, version)}/topic" - - def _topic_url(self, model_id: str, topic_name: str, version:str='v1') -> str: - """ - Get the URL for a specific topic. - Args: - model_id (str): The ID of the model. - topic_name (str): The name of the topic. - Returns: - str: The URL for the specified topic. - """ - return f"{self._base_topic_url(model_id, version)}/{topic_name}" - - def _base_view_url(self, model_id: str, version:str='v1') -> str: - """ - Get the base URL for view operations. - Args: - model_id (str): The ID of the model. - Returns: - str: The base URL for view operations. - """ - return f"{self._base_model_url(version)}/{model_id}/view" - - def _view_url(self, model_id: str, view_name: str, version:str='v1') -> str: - """ - Get the URL for a specific view. - Args: - model_id (str): The ID of the model. - view_name (str): The name of the view. - Returns: - str: The URL for the specified view. - """ - return f"{self._base_model_url(model_id, version)}/{view_name}" - - def _base_field_url(self, model_id: str, version:str='v1') -> str: - """ - Get the base URL for field operations. - Args: - model_id (str): The ID of the model. - Returns: - str: The base URL for field operations. - """ - return f"{self._base_view_url(model_id, version)}/field" - - def _field_url(self, model_id: str, view_name: str, field_name: str, version:str='v1') -> str: - """ - Get the URL for a specific field. - Args: - model_id (str): The ID of the model. - view_name (str): The name of the view. - field_name (str): The name of the field. - Returns: - str: The URL for the specified field. - """ - return f"{self._view_url(model_id, view_name, version)}/field/{field_name}" - - @requests_error_handler - def create_model(self, connection_id: str, body: dict, version:str='v1') -> dict: - """ - Create a new model. - Args: - connection_id (str): The connection ID. - body (dict): The model creation body. - Returns: - dict: The created model information. - Raises: - requests.exceptions.RequestException: If the API request fails. - """ - url = self._base_model_url(version) - body["connectionId"] = connection_id - response = requests.post(url, headers=self.headers, json=body) - response.raise_for_status() - return response.json() - - @requests_error_handler - def create_topic(self, model_id: str, base_view_name: str, body: dict, version:str='v1') -> dict: - """ - Create a new topic. - Args: - model_id (str): The ID of the model. - base_view_name (str): The name of the base view. - body (dict): The topic creation body. - Returns: - dict: The created topic information. - Raises: - requests.exceptions.RequestException: If the API request fails. - """ - url = self._base_topic_url(model_id, version) - body["baseViewName"] = base_view_name - response = requests.post(url, headers=self.headers, json=body) - response.raise_for_status() - return response.json() - - @requests_error_handler - def update_topic(self, model_id: str, topic_name: str, body: dict, version:str='v1') -> dict: - """ - Update an existing topic. - Args: - model_id (str): The ID of the model. - topic_name (str): The name of the topic to update. - body (dict): The topic update body. - Returns: - dict: The updated topic information. - Raises: - requests.exceptions.RequestException: If the API request fails. - """ - url = self._topic_url(model_id, topic_name, version) - response = requests.patch(url, headers=self.headers, json=body) - response.raise_for_status() - return response.json() - - @requests_error_handler - def delete_topic(self, model_id: str, topic_name: str, version:str='v1') -> dict: - """ - Delete a topic. - Args: - model_id (str): The ID of the model. - topic_name (str): The name of the topic to delete. - Returns: - dict: The response from the delete operation. - Raises: - requests.exceptions.RequestException: If the API request fails. - """ - url = self._topic_url(model_id, topic_name, version) - response = requests.delete(url, headers=self.headers) - response.raise_for_status() - return response.json() - - @requests_error_handler - def get_topic(self, model_id: str, topic_name: str, version:str='unstable') -> dict: - """ - Get a topic by its name. - Args: - model_id (str): The ID of the model. - topic_name (str): The name of the topic to get. - Returns: - dict: The topic information. - Raises: - requests.exceptions.RequestException: If the API request fails. - """ - url = self._topic_url(model_id, topic_name, version) - response = requests.get(url, headers=self.headers) - - payload = response.json() - if not payload['success']: - response.raise_for_status() - return payload['topic'] diff --git a/omni_python_sdk/api/__init__.py b/omni_python_sdk/api/__init__.py new file mode 100644 index 0000000..81f9fa2 --- /dev/null +++ b/omni_python_sdk/api/__init__.py @@ -0,0 +1 @@ +"""Contains methods for accessing the API""" diff --git a/omni_python_sdk/api/ai/__init__.py b/omni_python_sdk/api/ai/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/ai/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/ai/ai_branding.py b/omni_python_sdk/api/ai/ai_branding.py new file mode 100644 index 0000000..4d802de --- /dev/null +++ b/omni_python_sdk/api/ai/ai_branding.py @@ -0,0 +1,160 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_branding_response import AiBrandingResponse +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/branding", + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiBrandingResponse | ApiError401 | ApiError403 | None: + if response.status_code == 200: + response_200 = AiBrandingResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiBrandingResponse | ApiError401 | ApiError403]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, +) -> Response[AiBrandingResponse | ApiError401 | ApiError403]: + """Get AI helper branding + + Returns the organization's AI helper branding — display name, optional custom logo URL, and copy + used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's + defaults when the organization hasn't configured custom branding, so the response is always + populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiBrandingResponse | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, +) -> AiBrandingResponse | ApiError401 | ApiError403 | None: + """Get AI helper branding + + Returns the organization's AI helper branding — display name, optional custom logo URL, and copy + used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's + defaults when the organization hasn't configured custom branding, so the response is always + populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiBrandingResponse | ApiError401 | ApiError403 + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, +) -> Response[AiBrandingResponse | ApiError401 | ApiError403]: + """Get AI helper branding + + Returns the organization's AI helper branding — display name, optional custom logo URL, and copy + used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's + defaults when the organization hasn't configured custom branding, so the response is always + populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiBrandingResponse | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, +) -> AiBrandingResponse | ApiError401 | ApiError403 | None: + """Get AI helper branding + + Returns the organization's AI helper branding — display name, optional custom logo URL, and copy + used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's + defaults when the organization hasn't configured custom branding, so the response is always + populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiBrandingResponse | ApiError401 | ApiError403 + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_conversation_detail.py b/omni_python_sdk/api/ai/ai_conversation_detail.py new file mode 100644 index 0000000..64cc1d7 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_conversation_detail.py @@ -0,0 +1,186 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_conversation_detail_response import AiConversationDetailResponse +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...types import Response + + +def _get_kwargs( + conversation_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/conversations/{conversation_id}".format( + conversation_id=quote(str(conversation_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiConversationDetailResponse | ApiError401 | ApiError403 | ApiError404 | None: + if response.status_code == 200: + response_200 = AiConversationDetailResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiConversationDetailResponse | ApiError401 | ApiError403 | ApiError404]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + conversation_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[AiConversationDetailResponse | ApiError401 | ApiError403 | ApiError404]: + """Get AI conversation with messages + + Return a conversation with its full message history (alternating user / assistant turns). Used by + clients (iOS app, embed widgets) to restore a prior conversation in their UI. + + Args: + conversation_id (UUID): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiConversationDetailResponse | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + conversation_id=conversation_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + conversation_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> AiConversationDetailResponse | ApiError401 | ApiError403 | ApiError404 | None: + """Get AI conversation with messages + + Return a conversation with its full message history (alternating user / assistant turns). Used by + clients (iOS app, embed widgets) to restore a prior conversation in their UI. + + Args: + conversation_id (UUID): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiConversationDetailResponse | ApiError401 | ApiError403 | ApiError404 + """ + + return sync_detailed( + conversation_id=conversation_id, + client=client, + ).parsed + + +async def asyncio_detailed( + conversation_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[AiConversationDetailResponse | ApiError401 | ApiError403 | ApiError404]: + """Get AI conversation with messages + + Return a conversation with its full message history (alternating user / assistant turns). Used by + clients (iOS app, embed widgets) to restore a prior conversation in their UI. + + Args: + conversation_id (UUID): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiConversationDetailResponse | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + conversation_id=conversation_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + conversation_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> AiConversationDetailResponse | ApiError401 | ApiError403 | ApiError404 | None: + """Get AI conversation with messages + + Return a conversation with its full message history (alternating user / assistant turns). Used by + clients (iOS app, embed widgets) to restore a prior conversation in their UI. + + Args: + conversation_id (UUID): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiConversationDetailResponse | ApiError401 | ApiError403 | ApiError404 + """ + + return ( + await asyncio_detailed( + conversation_id=conversation_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_conversations_list.py b/omni_python_sdk/api/ai/ai_conversations_list.py new file mode 100644 index 0000000..ef418a8 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_conversations_list.py @@ -0,0 +1,238 @@ +from http import HTTPStatus +from typing import Any +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_conversations_list_response import AiConversationsListResponse +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["pageSize"] = page_size + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/conversations", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiConversationsListResponse | ApiError401 | ApiError403 | None: + if response.status_code == 200: + response_200 = AiConversationsListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiConversationsListResponse | ApiError401 | ApiError403]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + user_id: UUID | Unset = UNSET, +) -> Response[AiConversationsListResponse | ApiError401 | ApiError403]: + """List AI conversations + + List the user's recent AI conversations, ordered by most-recent activity. Each record includes the + conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to + continue the thread), an optional name, and a one-line summary of the most recent prompt for + display. Paginated via opaque `pageInfo.nextCursor` — pass it back as `cursor` to fetch the next + page. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiConversationsListResponse | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + user_id: UUID | Unset = UNSET, +) -> AiConversationsListResponse | ApiError401 | ApiError403 | None: + """List AI conversations + + List the user's recent AI conversations, ordered by most-recent activity. Each record includes the + conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to + continue the thread), an optional name, and a one-line summary of the most recent prompt for + display. Paginated via opaque `pageInfo.nextCursor` — pass it back as `cursor` to fetch the next + page. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiConversationsListResponse | ApiError401 | ApiError403 + """ + + return sync_detailed( + client=client, + cursor=cursor, + page_size=page_size, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + user_id: UUID | Unset = UNSET, +) -> Response[AiConversationsListResponse | ApiError401 | ApiError403]: + """List AI conversations + + List the user's recent AI conversations, ordered by most-recent activity. Each record includes the + conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to + continue the thread), an optional name, and a one-line summary of the most recent prompt for + display. Paginated via opaque `pageInfo.nextCursor` — pass it back as `cursor` to fetch the next + page. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiConversationsListResponse | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + user_id: UUID | Unset = UNSET, +) -> AiConversationsListResponse | ApiError401 | ApiError403 | None: + """List AI conversations + + List the user's recent AI conversations, ordered by most-recent activity. Each record includes the + conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to + continue the thread), an optional name, and a one-line summary of the most recent prompt for + display. Paginated via opaque `pageInfo.nextCursor` — pass it back as `cursor` to fetch the next + page. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiConversationsListResponse | ApiError401 | ApiError403 + """ + + return ( + await asyncio_detailed( + client=client, + cursor=cursor, + page_size=page_size, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_credit_controls_get.py b/omni_python_sdk/api/ai/ai_credit_controls_get.py new file mode 100644 index 0000000..1ee87d2 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_credit_controls_get.py @@ -0,0 +1,160 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_credit_controls_response import AiCreditControlsResponse +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/credit-controls", + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiCreditControlsResponse | ApiError401 | ApiError403 | None: + if response.status_code == 200: + response_200 = AiCreditControlsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiCreditControlsResponse | ApiError401 | ApiError403]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, +) -> Response[AiCreditControlsResponse | ApiError401 | ApiError403]: + """Get AI credit controls + + Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per- + user credit limit, plus read-only context (the credit limit, usage so far this billing period, and + the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same + AI-admin permission. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiCreditControlsResponse | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, +) -> AiCreditControlsResponse | ApiError401 | ApiError403 | None: + """Get AI credit controls + + Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per- + user credit limit, plus read-only context (the credit limit, usage so far this billing period, and + the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same + AI-admin permission. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiCreditControlsResponse | ApiError401 | ApiError403 + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, +) -> Response[AiCreditControlsResponse | ApiError401 | ApiError403]: + """Get AI credit controls + + Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per- + user credit limit, plus read-only context (the credit limit, usage so far this billing period, and + the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same + AI-admin permission. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiCreditControlsResponse | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, +) -> AiCreditControlsResponse | ApiError401 | ApiError403 | None: + """Get AI credit controls + + Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per- + user credit limit, plus read-only context (the credit limit, usage so far this billing period, and + the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same + AI-admin permission. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiCreditControlsResponse | ApiError401 | ApiError403 + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_credit_controls_update.py b/omni_python_sdk/api/ai/ai_credit_controls_update.py new file mode 100644 index 0000000..aadbcd9 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_credit_controls_update.py @@ -0,0 +1,206 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_credit_controls_response import AiCreditControlsResponse +from ...models.ai_credit_controls_update_body import AiCreditControlsUpdateBody +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...types import Response + + +def _get_kwargs( + *, + body: AiCreditControlsUpdateBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/ai/credit-controls", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403 | None: + if response.status_code == 200: + response_200 = AiCreditControlsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: AiCreditControlsUpdateBody, +) -> Response[AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403]: + """Update AI credit controls + + Update the organization's AI credit controls: the downgrade and shutoff thresholds and the default + per-user credit limit (userDefaultCredits). All fields are optional and tri-state: omit a field to + leave it unchanged, send `null` to turn that control off (for userDefaultCredits: unlimited by + default), or send a non-negative number to set it. At least one field is required. The + `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the + full current state, the same shape as GET. + + Args: + body (AiCreditControlsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: AiCreditControlsUpdateBody, +) -> AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403 | None: + """Update AI credit controls + + Update the organization's AI credit controls: the downgrade and shutoff thresholds and the default + per-user credit limit (userDefaultCredits). All fields are optional and tri-state: omit a field to + leave it unchanged, send `null` to turn that control off (for userDefaultCredits: unlimited by + default), or send a non-negative number to set it. At least one field is required. The + `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the + full current state, the same shape as GET. + + Args: + body (AiCreditControlsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403 + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: AiCreditControlsUpdateBody, +) -> Response[AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403]: + """Update AI credit controls + + Update the organization's AI credit controls: the downgrade and shutoff thresholds and the default + per-user credit limit (userDefaultCredits). All fields are optional and tri-state: omit a field to + leave it unchanged, send `null` to turn that control off (for userDefaultCredits: unlimited by + default), or send a non-negative number to set it. At least one field is required. The + `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the + full current state, the same shape as GET. + + Args: + body (AiCreditControlsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: AiCreditControlsUpdateBody, +) -> AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403 | None: + """Update AI credit controls + + Update the organization's AI credit controls: the downgrade and shutoff thresholds and the default + per-user credit limit (userDefaultCredits). All fields are optional and tri-state: omit a field to + leave it unchanged, send `null` to turn that control off (for userDefaultCredits: unlimited by + default), or send a non-negative number to set it. At least one field is required. The + `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the + full current state, the same shape as GET. + + Args: + body (AiCreditControlsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403 + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_credit_controls_users_list.py b/omni_python_sdk/api/ai/ai_credit_controls_users_list.py new file mode 100644 index 0000000..9cf07f8 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_credit_controls_users_list.py @@ -0,0 +1,225 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_credit_controls_users_list_response import AiCreditControlsUsersListResponse +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["pageSize"] = page_size + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/credit-controls/users", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiCreditControlsUsersListResponse | ApiError400 | ApiError401 | ApiError403 | None: + if response.status_code == 200: + response_200 = AiCreditControlsUsersListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiCreditControlsUsersListResponse | ApiError400 | ApiError401 | ApiError403]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, +) -> Response[AiCreditControlsUsersListResponse | ApiError400 | ApiError401 | ApiError403]: + """List individual users' AI credit limits + + List the organization's active individual user AI credit limits, ordered by userId ascending. Only + users with an individual limit appear — everyone else follows the org default. A `null` creditLimit + is an explicit unlimited override, distinct from following the default. Paginated via opaque + cursors: pass `pageInfo.nextCursor` from one response as the `cursor` query parameter on the next + request. Requires the same manage-user-attributes permission as the PATCH. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiCreditControlsUsersListResponse | ApiError400 | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, +) -> AiCreditControlsUsersListResponse | ApiError400 | ApiError401 | ApiError403 | None: + """List individual users' AI credit limits + + List the organization's active individual user AI credit limits, ordered by userId ascending. Only + users with an individual limit appear — everyone else follows the org default. A `null` creditLimit + is an explicit unlimited override, distinct from following the default. Paginated via opaque + cursors: pass `pageInfo.nextCursor` from one response as the `cursor` query parameter on the next + request. Requires the same manage-user-attributes permission as the PATCH. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiCreditControlsUsersListResponse | ApiError400 | ApiError401 | ApiError403 + """ + + return sync_detailed( + client=client, + cursor=cursor, + page_size=page_size, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, +) -> Response[AiCreditControlsUsersListResponse | ApiError400 | ApiError401 | ApiError403]: + """List individual users' AI credit limits + + List the organization's active individual user AI credit limits, ordered by userId ascending. Only + users with an individual limit appear — everyone else follows the org default. A `null` creditLimit + is an explicit unlimited override, distinct from following the default. Paginated via opaque + cursors: pass `pageInfo.nextCursor` from one response as the `cursor` query parameter on the next + request. Requires the same manage-user-attributes permission as the PATCH. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiCreditControlsUsersListResponse | ApiError400 | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, +) -> AiCreditControlsUsersListResponse | ApiError400 | ApiError401 | ApiError403 | None: + """List individual users' AI credit limits + + List the organization's active individual user AI credit limits, ordered by userId ascending. Only + users with an individual limit appear — everyone else follows the org default. A `null` creditLimit + is an explicit unlimited override, distinct from following the default. Paginated via opaque + cursors: pass `pageInfo.nextCursor` from one response as the `cursor` query parameter on the next + request. Requires the same manage-user-attributes permission as the PATCH. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiCreditControlsUsersListResponse | ApiError400 | ApiError401 | ApiError403 + """ + + return ( + await asyncio_detailed( + client=client, + cursor=cursor, + page_size=page_size, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_credit_controls_users_update.py b/omni_python_sdk/api/ai/ai_credit_controls_users_update.py new file mode 100644 index 0000000..4c0ef7b --- /dev/null +++ b/omni_python_sdk/api/ai/ai_credit_controls_users_update.py @@ -0,0 +1,212 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_user_credit_limits_response import AiUserCreditLimitsResponse +from ...models.ai_user_credit_limits_update_body import AiUserCreditLimitsUpdateBody +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...types import Response + + +def _get_kwargs( + *, + body: AiUserCreditLimitsUpdateBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/ai/credit-controls/users", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiUserCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + if response.status_code == 200: + response_200 = AiUserCreditLimitsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiUserCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: AiUserCreditLimitsUpdateBody, +) -> Response[AiUserCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + """Set individual users' AI credit limits + + Set individual users' AI credit limits in bulk. Each entry names a user (`userId`) and either sets + an individual limit (`creditLimit`: a non-negative number, or `null` for unlimited) or removes one + (`useDefaultLimit: true`) so the user follows the org default. Each userId may appear at most once + and must be a member of the organization. All updates are applied in one transaction, so either + every entry takes effect or none do — an invalid userId fails the whole request with a 404 naming + it. Requires the same manage-user-attributes permission as the AI credit limit settings pages. + + Args: + body (AiUserCreditLimitsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiUserCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: AiUserCreditLimitsUpdateBody, +) -> AiUserCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + """Set individual users' AI credit limits + + Set individual users' AI credit limits in bulk. Each entry names a user (`userId`) and either sets + an individual limit (`creditLimit`: a non-negative number, or `null` for unlimited) or removes one + (`useDefaultLimit: true`) so the user follows the org default. Each userId may appear at most once + and must be a member of the organization. All updates are applied in one transaction, so either + every entry takes effect or none do — an invalid userId fails the whole request with a 404 naming + it. Requires the same manage-user-attributes permission as the AI credit limit settings pages. + + Args: + body (AiUserCreditLimitsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiUserCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: AiUserCreditLimitsUpdateBody, +) -> Response[AiUserCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + """Set individual users' AI credit limits + + Set individual users' AI credit limits in bulk. Each entry names a user (`userId`) and either sets + an individual limit (`creditLimit`: a non-negative number, or `null` for unlimited) or removes one + (`useDefaultLimit: true`) so the user follows the org default. Each userId may appear at most once + and must be a member of the organization. All updates are applied in one transaction, so either + every entry takes effect or none do — an invalid userId fails the whole request with a 404 naming + it. Requires the same manage-user-attributes permission as the AI credit limit settings pages. + + Args: + body (AiUserCreditLimitsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiUserCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: AiUserCreditLimitsUpdateBody, +) -> AiUserCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + """Set individual users' AI credit limits + + Set individual users' AI credit limits in bulk. Each entry names a user (`userId`) and either sets + an individual limit (`creditLimit`: a non-negative number, or `null` for unlimited) or removes one + (`useDefaultLimit: true`) so the user follows the org default. Each userId may appear at most once + and must be a member of the organization. All updates are applied in one transaction, so either + every entry takes effect or none do — an invalid userId fails the whole request with a 404 naming + it. Requires the same manage-user-attributes permission as the AI credit limit settings pages. + + Args: + body (AiUserCreditLimitsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiUserCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_generate_query.py b/omni_python_sdk/api/ai/ai_generate_query.py new file mode 100644 index 0000000..1543600 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_generate_query.py @@ -0,0 +1,222 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_credit_shutoff_error import AiCreditShutoffError +from ...models.ai_generate_query_body import AiGenerateQueryBody +from ...models.ai_generate_query_response import AiGenerateQueryResponse +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...types import Response + + +def _get_kwargs( + *, + body: AiGenerateQueryBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/ai/generate-query", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ( + AiCreditShutoffError | AiGenerateQueryResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None +): + if response.status_code == 200: + response_200 = AiGenerateQueryResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 402: + response_402 = AiCreditShutoffError.from_dict(response.json()) + + return response_402 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ + AiCreditShutoffError | AiGenerateQueryResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 +]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: AiGenerateQueryBody, +) -> Response[ + AiCreditShutoffError | AiGenerateQueryResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 +]: + """Generate query from natural language + + Generate an Omni semantic query from a natural language prompt. Optionally executes the generated + query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from + the model, and constructs a query. Requires the querier role on the target model. + + Args: + body (AiGenerateQueryBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiCreditShutoffError | AiGenerateQueryResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: AiGenerateQueryBody, +) -> ( + AiCreditShutoffError | AiGenerateQueryResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None +): + """Generate query from natural language + + Generate an Omni semantic query from a natural language prompt. Optionally executes the generated + query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from + the model, and constructs a query. Requires the querier role on the target model. + + Args: + body (AiGenerateQueryBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiCreditShutoffError | AiGenerateQueryResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: AiGenerateQueryBody, +) -> Response[ + AiCreditShutoffError | AiGenerateQueryResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 +]: + """Generate query from natural language + + Generate an Omni semantic query from a natural language prompt. Optionally executes the generated + query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from + the model, and constructs a query. Requires the querier role on the target model. + + Args: + body (AiGenerateQueryBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiCreditShutoffError | AiGenerateQueryResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: AiGenerateQueryBody, +) -> ( + AiCreditShutoffError | AiGenerateQueryResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None +): + """Generate query from natural language + + Generate an Omni semantic query from a natural language prompt. Optionally executes the generated + query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from + the model, and constructs a query. Requires the querier role on the target model. + + Args: + body (AiGenerateQueryBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiCreditShutoffError | AiGenerateQueryResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_job_cancel.py b/omni_python_sdk/api/ai/ai_job_cancel.py new file mode 100644 index 0000000..0be2e40 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_job_cancel.py @@ -0,0 +1,214 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_job_cancel_response import AiJobCancelResponse +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...models.api_error_409 import ApiError409 +from ...types import Response + + +def _get_kwargs( + job_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/ai/jobs/{job_id}/cancel".format( + job_id=quote(str(job_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiJobCancelResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | None: + if response.status_code == 200: + response_200 = AiJobCancelResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = ApiError409.from_dict(response.json()) + + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiJobCancelResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[AiJobCancelResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409]: + """Cancel an AI job + + Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled + or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. + For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING + state cannot be cancelled as they are already finalizing results. Only the job owner or organization + admins can cancel jobs. + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiJobCancelResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409] + """ + + kwargs = _get_kwargs( + job_id=job_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> AiJobCancelResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | None: + """Cancel an AI job + + Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled + or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. + For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING + state cannot be cancelled as they are already finalizing results. Only the job owner or organization + admins can cancel jobs. + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiJobCancelResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 + """ + + return sync_detailed( + job_id=job_id, + client=client, + ).parsed + + +async def asyncio_detailed( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[AiJobCancelResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409]: + """Cancel an AI job + + Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled + or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. + For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING + state cannot be cancelled as they are already finalizing results. Only the job owner or organization + admins can cancel jobs. + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiJobCancelResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409] + """ + + kwargs = _get_kwargs( + job_id=job_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> AiJobCancelResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | None: + """Cancel an AI job + + Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled + or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. + For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING + state cannot be cancelled as they are already finalizing results. Only the job owner or organization + admins can cancel jobs. + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiJobCancelResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 + """ + + return ( + await asyncio_detailed( + job_id=job_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_job_result.py b/omni_python_sdk/api/ai/ai_job_result.py new file mode 100644 index 0000000..37d3e59 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_job_result.py @@ -0,0 +1,204 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_job_result_response import AiJobResultResponse +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...types import Response + + +def _get_kwargs( + job_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/jobs/{job_id}/result".format( + job_id=quote(str(job_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiJobResultResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + if response.status_code == 200: + response_200 = AiJobResultResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiJobResultResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[AiJobResultResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + """Get AI job result + + Retrieve the full result of a completed AI job, including all actions taken by the AI (queries + generated, data retrieved) and the final summarized answer. Results are only available for jobs in + COMPLETE state and are retained for 14 days after completion. The response is streamed directly from + storage. + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiJobResultResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + job_id=job_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> AiJobResultResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + """Get AI job result + + Retrieve the full result of a completed AI job, including all actions taken by the AI (queries + generated, data retrieved) and the final summarized answer. Results are only available for jobs in + COMPLETE state and are retained for 14 days after completion. The response is streamed directly from + storage. + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiJobResultResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 + """ + + return sync_detailed( + job_id=job_id, + client=client, + ).parsed + + +async def asyncio_detailed( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[AiJobResultResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + """Get AI job result + + Retrieve the full result of a completed AI job, including all actions taken by the AI (queries + generated, data retrieved) and the final summarized answer. Results are only available for jobs in + COMPLETE state and are retained for 14 days after completion. The response is streamed directly from + storage. + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiJobResultResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + job_id=job_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> AiJobResultResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + """Get AI job result + + Retrieve the full result of a completed AI job, including all actions taken by the AI (queries + generated, data retrieved) and the final summarized answer. Results are only available for jobs in + COMPLETE state and are retained for 14 days after completion. The response is streamed directly from + storage. + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiJobResultResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 + """ + + return ( + await asyncio_detailed( + job_id=job_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_job_status.py b/omni_python_sdk/api/ai/ai_job_status.py new file mode 100644 index 0000000..8d2f40b --- /dev/null +++ b/omni_python_sdk/api/ai/ai_job_status.py @@ -0,0 +1,204 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_job_status_response import AiJobStatusResponse +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...types import Response + + +def _get_kwargs( + job_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/jobs/{job_id}".format( + job_id=quote(str(job_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiJobStatusResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + if response.status_code == 200: + response_200 = AiJobStatusResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiJobStatusResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[AiJobStatusResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + """Get AI job status + + Get the current status of an AI job, including its state, progress information, and result summary. + The response fields vary by state — for example, progress is only present during EXECUTING, and + resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job + reaches a terminal state (COMPLETE, FAILED, or CANCELLED). + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiJobStatusResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + job_id=job_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> AiJobStatusResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + """Get AI job status + + Get the current status of an AI job, including its state, progress information, and result summary. + The response fields vary by state — for example, progress is only present during EXECUTING, and + resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job + reaches a terminal state (COMPLETE, FAILED, or CANCELLED). + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiJobStatusResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 + """ + + return sync_detailed( + job_id=job_id, + client=client, + ).parsed + + +async def asyncio_detailed( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[AiJobStatusResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + """Get AI job status + + Get the current status of an AI job, including its state, progress information, and result summary. + The response fields vary by state — for example, progress is only present during EXECUTING, and + resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job + reaches a terminal state (COMPLETE, FAILED, or CANCELLED). + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiJobStatusResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + job_id=job_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> AiJobStatusResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + """Get AI job status + + Get the current status of an AI job, including its state, progress information, and result summary. + The response fields vary by state — for example, progress is only present during EXECUTING, and + resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job + reaches a terminal state (COMPLETE, FAILED, or CANCELLED). + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiJobStatusResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 + """ + + return ( + await asyncio_detailed( + job_id=job_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_job_submit.py b/omni_python_sdk/api/ai/ai_job_submit.py new file mode 100644 index 0000000..78539f1 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_job_submit.py @@ -0,0 +1,238 @@ +from http import HTTPStatus +from typing import Any +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_job_submit_body import AiJobSubmitBody +from ...models.ai_job_submit_response import AiJobSubmitResponse +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...models.api_error_409 import ApiError409 +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: AiJobSubmitBody, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/ai/jobs", + "params": params, + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiJobSubmitResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | None: + if response.status_code == 201: + response_201 = AiJobSubmitResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = ApiError409.from_dict(response.json()) + + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiJobSubmitResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: AiJobSubmitBody, + user_id: UUID | Unset = UNSET, +) -> Response[AiJobSubmitResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409]: + """Submit an AI job + + Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute + queries against the specified model, and produce a summarized answer. Jobs are processed by a + background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to + poll for status, or configure a webhookUrl to receive a notification when the job completes. + Optionally continue an existing conversation by providing a conversationId. + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (AiJobSubmitBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiJobSubmitResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409] + """ + + kwargs = _get_kwargs( + body=body, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: AiJobSubmitBody, + user_id: UUID | Unset = UNSET, +) -> AiJobSubmitResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | None: + """Submit an AI job + + Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute + queries against the specified model, and produce a summarized answer. Jobs are processed by a + background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to + poll for status, or configure a webhookUrl to receive a notification when the job completes. + Optionally continue an existing conversation by providing a conversationId. + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (AiJobSubmitBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiJobSubmitResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 + """ + + return sync_detailed( + client=client, + body=body, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: AiJobSubmitBody, + user_id: UUID | Unset = UNSET, +) -> Response[AiJobSubmitResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409]: + """Submit an AI job + + Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute + queries against the specified model, and produce a summarized answer. Jobs are processed by a + background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to + poll for status, or configure a webhookUrl to receive a notification when the job completes. + Optionally continue an existing conversation by providing a conversationId. + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (AiJobSubmitBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiJobSubmitResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409] + """ + + kwargs = _get_kwargs( + body=body, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: AiJobSubmitBody, + user_id: UUID | Unset = UNSET, +) -> AiJobSubmitResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | None: + """Submit an AI job + + Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute + queries against the specified model, and produce a summarized answer. Jobs are processed by a + background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to + poll for status, or configure a webhookUrl to receive a notification when the job completes. + Optionally continue an existing conversation by providing a conversationId. + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (AiJobSubmitBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiJobSubmitResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_job_visualization.py b/omni_python_sdk/api/ai/ai_job_visualization.py new file mode 100644 index 0000000..1f3fcb9 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_job_visualization.py @@ -0,0 +1,204 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...models.api_error_422 import ApiError422 +from ...types import Response + + +def _get_kwargs( + job_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/jobs/{job_id}/vis".format( + job_id=quote(str(job_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError422 | None: + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = ApiError422.from_dict(response.json()) + + return response_422 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError422]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError422]: + r"""Render AI job visualization + + Render the visualization from a completed AI job as a PNG image. The endpoint extracts the + visualization configuration from the job result, loads Arrow IPC data, and renders it server-side + using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back + through previous jobs in the conversation to find the original query data. + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError422] + """ + + kwargs = _get_kwargs( + job_id=job_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError422 | None: + r"""Render AI job visualization + + Render the visualization from a completed AI job as a PNG image. The endpoint extracts the + visualization configuration from the job result, loads Arrow IPC data, and renders it server-side + using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back + through previous jobs in the conversation to find the original query data. + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError422 + """ + + return sync_detailed( + job_id=job_id, + client=client, + ).parsed + + +async def asyncio_detailed( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError422]: + r"""Render AI job visualization + + Render the visualization from a completed AI job as a PNG image. The endpoint extracts the + visualization configuration from the job result, loads Arrow IPC data, and renders it server-side + using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back + through previous jobs in the conversation to find the original query data. + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError422] + """ + + kwargs = _get_kwargs( + job_id=job_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + job_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError422 | None: + r"""Render AI job visualization + + Render the visualization from a completed AI job as a PNG image. The endpoint extracts the + visualization configuration from the job result, loads Arrow IPC data, and renders it server-side + using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back + through previous jobs in the conversation to find the original query data. + + Args: + job_id (UUID): The unique identifier of the AI job Example: + 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError422 + """ + + return ( + await asyncio_detailed( + job_id=job_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_pick_topic.py b/omni_python_sdk/api/ai/ai_pick_topic.py new file mode 100644 index 0000000..6aa7f6b --- /dev/null +++ b/omni_python_sdk/api/ai/ai_pick_topic.py @@ -0,0 +1,204 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_pick_topic_body import AiPickTopicBody +from ...models.ai_pick_topic_response import AiPickTopicResponse +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...types import Response + + +def _get_kwargs( + *, + body: AiPickTopicBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/ai/pick-topic", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiPickTopicResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + if response.status_code == 200: + response_200 = AiPickTopicResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiPickTopicResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: AiPickTopicBody, +) -> Response[AiPickTopicResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + """Pick the best topic for a prompt + + Analyze a natural language prompt and determine which topic in the model is the best fit for + answering the question. Useful as a preprocessing step before calling generate-query or submitting + an AI job, especially when the user's question could relate to multiple topics. + + Args: + body (AiPickTopicBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiPickTopicResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: AiPickTopicBody, +) -> AiPickTopicResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + """Pick the best topic for a prompt + + Analyze a natural language prompt and determine which topic in the model is the best fit for + answering the question. Useful as a preprocessing step before calling generate-query or submitting + an AI job, especially when the user's question could relate to multiple topics. + + Args: + body (AiPickTopicBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiPickTopicResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: AiPickTopicBody, +) -> Response[AiPickTopicResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + """Pick the best topic for a prompt + + Analyze a natural language prompt and determine which topic in the model is the best fit for + answering the question. Useful as a preprocessing step before calling generate-query or submitting + an AI job, especially when the user's question could relate to multiple topics. + + Args: + body (AiPickTopicBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiPickTopicResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: AiPickTopicBody, +) -> AiPickTopicResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + """Pick the best topic for a prompt + + Analyze a natural language prompt and determine which topic in the model is the best fit for + answering the question. Useful as a preprocessing step before calling generate-query or submitting + an AI job, especially when the user's question could relate to multiple topics. + + Args: + body (AiPickTopicBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiPickTopicResponse | Any | ApiError400 | ApiError401 | ApiError403 | ApiError404 + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_search_omni_docs.py b/omni_python_sdk/api/ai/ai_search_omni_docs.py new file mode 100644 index 0000000..16d1430 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_search_omni_docs.py @@ -0,0 +1,198 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_search_omni_docs_body import AiSearchOmniDocsBody +from ...models.ai_search_omni_docs_response import AiSearchOmniDocsResponse +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...types import Response + + +def _get_kwargs( + *, + body: AiSearchOmniDocsBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/ai/search-omni-docs", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiSearchOmniDocsResponse | Any | ApiError400 | ApiError401 | ApiError403 | None: + if response.status_code == 200: + response_200 = AiSearchOmniDocsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiSearchOmniDocsResponse | Any | ApiError400 | ApiError401 | ApiError403]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: AiSearchOmniDocsBody, +) -> Response[AiSearchOmniDocsResponse | Any | ApiError400 | ApiError401 | ApiError403]: + """Search Omni documentation + + Search the Omni documentation using AI to answer questions about Omni features, configuration, + modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer + with source links to the relevant documentation pages. + + Args: + body (AiSearchOmniDocsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiSearchOmniDocsResponse | Any | ApiError400 | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: AiSearchOmniDocsBody, +) -> AiSearchOmniDocsResponse | Any | ApiError400 | ApiError401 | ApiError403 | None: + """Search Omni documentation + + Search the Omni documentation using AI to answer questions about Omni features, configuration, + modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer + with source links to the relevant documentation pages. + + Args: + body (AiSearchOmniDocsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiSearchOmniDocsResponse | Any | ApiError400 | ApiError401 | ApiError403 + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: AiSearchOmniDocsBody, +) -> Response[AiSearchOmniDocsResponse | Any | ApiError400 | ApiError401 | ApiError403]: + """Search Omni documentation + + Search the Omni documentation using AI to answer questions about Omni features, configuration, + modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer + with source links to the relevant documentation pages. + + Args: + body (AiSearchOmniDocsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiSearchOmniDocsResponse | Any | ApiError400 | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: AiSearchOmniDocsBody, +) -> AiSearchOmniDocsResponse | Any | ApiError400 | ApiError401 | ApiError403 | None: + """Search Omni documentation + + Search the Omni documentation using AI to answer questions about Omni features, configuration, + modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer + with source links to the relevant documentation pages. + + Args: + body (AiSearchOmniDocsBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiSearchOmniDocsResponse | Any | ApiError400 | ApiError401 | ApiError403 + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_eval/__init__.py b/omni_python_sdk/api/ai_eval/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/ai_eval/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_archive.py b/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_archive.py new file mode 100644 index 0000000..525bdb9 --- /dev/null +++ b/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_archive.py @@ -0,0 +1,263 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.eval_api_error_400 import EvalApiError400 +from ...models.eval_api_error_401 import EvalApiError401 +from ...models.eval_api_error_403 import EvalApiError403 +from ...models.eval_api_error_404 import EvalApiError404 +from ...models.eval_api_error_500 import EvalApiError500 +from ...models.eval_prompt_sets_delete_response import EvalPromptSetsDeleteResponse +from ...types import Response + + +def _get_kwargs( + prompt_set_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/ai/eval/prompt-sets/{prompt_set_id}".format( + prompt_set_id=quote(str(prompt_set_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ( + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError500 + | EvalPromptSetsDeleteResponse + | None +): + if response.status_code == 200: + response_200 = EvalPromptSetsDeleteResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = EvalApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = EvalApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = EvalApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = EvalApiError404.from_dict(response.json()) + + return response_404 + + if response.status_code == 500: + response_500 = EvalApiError500.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError500 + | EvalPromptSetsDeleteResponse +]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[ + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError500 + | EvalPromptSetsDeleteResponse +]: + """Archive an eval prompt set + + Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight + agentic job associated with the set; the returned `cancelled_job_count` reports how many were + cancelled. The archive is committed before run cancellations start. Cancellation is best-effort — + the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. + If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt + set is already archived. The call is idempotent — retrying drains any remaining runs. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalPromptSetsDeleteResponse] + """ + + kwargs = _get_kwargs( + prompt_set_id=prompt_set_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> ( + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError500 + | EvalPromptSetsDeleteResponse + | None +): + """Archive an eval prompt set + + Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight + agentic job associated with the set; the returned `cancelled_job_count` reports how many were + cancelled. The archive is committed before run cancellations start. Cancellation is best-effort — + the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. + If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt + set is already archived. The call is idempotent — retrying drains any remaining runs. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalPromptSetsDeleteResponse + """ + + return sync_detailed( + prompt_set_id=prompt_set_id, + client=client, + ).parsed + + +async def asyncio_detailed( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[ + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError500 + | EvalPromptSetsDeleteResponse +]: + """Archive an eval prompt set + + Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight + agentic job associated with the set; the returned `cancelled_job_count` reports how many were + cancelled. The archive is committed before run cancellations start. Cancellation is best-effort — + the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. + If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt + set is already archived. The call is idempotent — retrying drains any remaining runs. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalPromptSetsDeleteResponse] + """ + + kwargs = _get_kwargs( + prompt_set_id=prompt_set_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> ( + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError500 + | EvalPromptSetsDeleteResponse + | None +): + """Archive an eval prompt set + + Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight + agentic job associated with the set; the returned `cancelled_job_count` reports how many were + cancelled. The archive is committed before run cancellations start. Cancellation is best-effort — + the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. + If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt + set is already archived. The call is idempotent — retrying drains any remaining runs. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalPromptSetsDeleteResponse + """ + + return ( + await asyncio_detailed( + prompt_set_id=prompt_set_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_create.py b/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_create.py new file mode 100644 index 0000000..c04b8e2 --- /dev/null +++ b/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_create.py @@ -0,0 +1,196 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.eval_api_error_400 import EvalApiError400 +from ...models.eval_api_error_401 import EvalApiError401 +from ...models.eval_api_error_403 import EvalApiError403 +from ...models.eval_api_error_422 import EvalApiError422 +from ...models.eval_prompt_sets_create_body import EvalPromptSetsCreateBody +from ...models.eval_prompt_sets_create_response import EvalPromptSetsCreateResponse +from ...types import Response + + +def _get_kwargs( + *, + body: EvalPromptSetsCreateBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/ai/eval/prompt-sets", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError422 | EvalPromptSetsCreateResponse | None: + if response.status_code == 201: + response_201 = EvalPromptSetsCreateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = EvalApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = EvalApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = EvalApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 422: + response_422 = EvalApiError422.from_dict(response.json()) + + return response_422 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError422 | EvalPromptSetsCreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: EvalPromptSetsCreateBody, +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError422 | EvalPromptSetsCreateResponse]: + """Create an eval prompt set + + Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional + prompts can be added later via PATCH. + + Args: + body (EvalPromptSetsCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError422 | EvalPromptSetsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: EvalPromptSetsCreateBody, +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError422 | EvalPromptSetsCreateResponse | None: + """Create an eval prompt set + + Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional + prompts can be added later via PATCH. + + Args: + body (EvalPromptSetsCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError422 | EvalPromptSetsCreateResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: EvalPromptSetsCreateBody, +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError422 | EvalPromptSetsCreateResponse]: + """Create an eval prompt set + + Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional + prompts can be added later via PATCH. + + Args: + body (EvalPromptSetsCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError422 | EvalPromptSetsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: EvalPromptSetsCreateBody, +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError422 | EvalPromptSetsCreateResponse | None: + """Create an eval prompt set + + Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional + prompts can be added later via PATCH. + + Args: + body (EvalPromptSetsCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError422 | EvalPromptSetsCreateResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_get.py b/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_get.py new file mode 100644 index 0000000..df7c0c1 --- /dev/null +++ b/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_get.py @@ -0,0 +1,192 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.eval_api_error_400 import EvalApiError400 +from ...models.eval_api_error_401 import EvalApiError401 +from ...models.eval_api_error_403 import EvalApiError403 +from ...models.eval_api_error_404 import EvalApiError404 +from ...models.eval_prompt_sets_get_response import EvalPromptSetsGetResponse +from ...types import Response + + +def _get_kwargs( + prompt_set_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/eval/prompt-sets/{prompt_set_id}".format( + prompt_set_id=quote(str(prompt_set_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsGetResponse | None: + if response.status_code == 200: + response_200 = EvalPromptSetsGetResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = EvalApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = EvalApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = EvalApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = EvalApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsGetResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsGetResponse]: + """Get an eval prompt set + + Get a single prompt set with all of its prompts. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsGetResponse] + """ + + kwargs = _get_kwargs( + prompt_set_id=prompt_set_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsGetResponse | None: + """Get an eval prompt set + + Get a single prompt set with all of its prompts. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsGetResponse + """ + + return sync_detailed( + prompt_set_id=prompt_set_id, + client=client, + ).parsed + + +async def asyncio_detailed( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsGetResponse]: + """Get an eval prompt set + + Get a single prompt set with all of its prompts. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsGetResponse] + """ + + kwargs = _get_kwargs( + prompt_set_id=prompt_set_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsGetResponse | None: + """Get an eval prompt set + + Get a single prompt set with all of its prompts. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsGetResponse + """ + + return ( + await asyncio_detailed( + prompt_set_id=prompt_set_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_list.py b/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_list.py new file mode 100644 index 0000000..0bc2d28 --- /dev/null +++ b/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_list.py @@ -0,0 +1,242 @@ +from http import HTTPStatus +from typing import Any +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_eval_prompt_sets_list_archived import ( + AiEvalPromptSetsListArchived, +) +from ...models.eval_api_error_400 import EvalApiError400 +from ...models.eval_api_error_401 import EvalApiError401 +from ...models.eval_api_error_403 import EvalApiError403 +from ...models.eval_api_error_404 import EvalApiError404 +from ...models.eval_prompt_sets_list_response import EvalPromptSetsListResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + archived: AiEvalPromptSetsListArchived | Unset = UNSET, + model_ids: list[UUID] | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_archived: str | Unset = UNSET + if not isinstance(archived, Unset): + json_archived = archived + + params["archived"] = json_archived + + json_model_ids: list[str] | Unset = UNSET + if not isinstance(model_ids, Unset): + json_model_ids = [] + for model_ids_item_data in model_ids: + model_ids_item = str(model_ids_item_data) + json_model_ids.append(model_ids_item) + + params["model_ids"] = json_model_ids + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/eval/prompt-sets", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsListResponse | None: + if response.status_code == 200: + response_200 = EvalPromptSetsListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = EvalApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = EvalApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = EvalApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = EvalApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + archived: AiEvalPromptSetsListArchived | Unset = UNSET, + model_ids: list[UUID] | Unset = UNSET, +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsListResponse]: + """List eval prompt sets + + List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt + sets for every shared model the caller can access. Requires at least the Querier role on each + requested model. + + Args: + archived (AiEvalPromptSetsListArchived | Unset): When `true`, returns archived prompt sets + instead of active ones. Defaults to `false`. Example: false. + model_ids (list[UUID] | Unset): Optional list of model IDs to filter prompt sets by. When + omitted, returns prompt sets for every model the caller can access. Supply multiple times + to filter by more than one model (e.g., `?model_ids=A&model_ids=B`). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsListResponse] + """ + + kwargs = _get_kwargs( + archived=archived, + model_ids=model_ids, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + archived: AiEvalPromptSetsListArchived | Unset = UNSET, + model_ids: list[UUID] | Unset = UNSET, +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsListResponse | None: + """List eval prompt sets + + List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt + sets for every shared model the caller can access. Requires at least the Querier role on each + requested model. + + Args: + archived (AiEvalPromptSetsListArchived | Unset): When `true`, returns archived prompt sets + instead of active ones. Defaults to `false`. Example: false. + model_ids (list[UUID] | Unset): Optional list of model IDs to filter prompt sets by. When + omitted, returns prompt sets for every model the caller can access. Supply multiple times + to filter by more than one model (e.g., `?model_ids=A&model_ids=B`). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsListResponse + """ + + return sync_detailed( + client=client, + archived=archived, + model_ids=model_ids, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + archived: AiEvalPromptSetsListArchived | Unset = UNSET, + model_ids: list[UUID] | Unset = UNSET, +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsListResponse]: + """List eval prompt sets + + List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt + sets for every shared model the caller can access. Requires at least the Querier role on each + requested model. + + Args: + archived (AiEvalPromptSetsListArchived | Unset): When `true`, returns archived prompt sets + instead of active ones. Defaults to `false`. Example: false. + model_ids (list[UUID] | Unset): Optional list of model IDs to filter prompt sets by. When + omitted, returns prompt sets for every model the caller can access. Supply multiple times + to filter by more than one model (e.g., `?model_ids=A&model_ids=B`). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsListResponse] + """ + + kwargs = _get_kwargs( + archived=archived, + model_ids=model_ids, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + archived: AiEvalPromptSetsListArchived | Unset = UNSET, + model_ids: list[UUID] | Unset = UNSET, +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsListResponse | None: + """List eval prompt sets + + List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt + sets for every shared model the caller can access. Requires at least the Querier role on each + requested model. + + Args: + archived (AiEvalPromptSetsListArchived | Unset): When `true`, returns archived prompt sets + instead of active ones. Defaults to `false`. Example: false. + model_ids (list[UUID] | Unset): Optional list of model IDs to filter prompt sets by. When + omitted, returns prompt sets for every model the caller can access. Supply multiple times + to filter by more than one model (e.g., `?model_ids=A&model_ids=B`). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsListResponse + """ + + return ( + await asyncio_detailed( + client=client, + archived=archived, + model_ids=model_ids, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_unarchive.py b/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_unarchive.py new file mode 100644 index 0000000..7b0e054 --- /dev/null +++ b/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_unarchive.py @@ -0,0 +1,192 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.eval_api_error_400 import EvalApiError400 +from ...models.eval_api_error_401 import EvalApiError401 +from ...models.eval_api_error_403 import EvalApiError403 +from ...models.eval_api_error_404 import EvalApiError404 +from ...models.eval_prompt_sets_unarchive_response import EvalPromptSetsUnarchiveResponse +from ...types import Response + + +def _get_kwargs( + prompt_set_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/ai/eval/prompt-sets/{prompt_set_id}/unarchive".format( + prompt_set_id=quote(str(prompt_set_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsUnarchiveResponse | None: + if response.status_code == 200: + response_200 = EvalPromptSetsUnarchiveResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = EvalApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = EvalApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = EvalApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = EvalApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsUnarchiveResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsUnarchiveResponse]: + """Restore an archived eval prompt set + + Restore an archived prompt set. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsUnarchiveResponse] + """ + + kwargs = _get_kwargs( + prompt_set_id=prompt_set_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsUnarchiveResponse | None: + """Restore an archived eval prompt set + + Restore an archived prompt set. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsUnarchiveResponse + """ + + return sync_detailed( + prompt_set_id=prompt_set_id, + client=client, + ).parsed + + +async def asyncio_detailed( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsUnarchiveResponse]: + """Restore an archived eval prompt set + + Restore an archived prompt set. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsUnarchiveResponse] + """ + + kwargs = _get_kwargs( + prompt_set_id=prompt_set_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsUnarchiveResponse | None: + """Restore an archived eval prompt set + + Restore an archived prompt set. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalPromptSetsUnarchiveResponse + """ + + return ( + await asyncio_detailed( + prompt_set_id=prompt_set_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_update.py b/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_update.py new file mode 100644 index 0000000..656b37a --- /dev/null +++ b/omni_python_sdk/api/ai_eval/ai_eval_prompt_sets_update.py @@ -0,0 +1,272 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.eval_api_error_400 import EvalApiError400 +from ...models.eval_api_error_401 import EvalApiError401 +from ...models.eval_api_error_403 import EvalApiError403 +from ...models.eval_api_error_404 import EvalApiError404 +from ...models.eval_api_error_422 import EvalApiError422 +from ...models.eval_prompt_sets_update_body import EvalPromptSetsUpdateBody +from ...models.eval_prompt_sets_update_response import EvalPromptSetsUpdateResponse +from ...types import Response + + +def _get_kwargs( + prompt_set_id: UUID, + *, + body: EvalPromptSetsUpdateBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/ai/eval/prompt-sets/{prompt_set_id}".format( + prompt_set_id=quote(str(prompt_set_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ( + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError422 + | EvalPromptSetsUpdateResponse + | None +): + if response.status_code == 200: + response_200 = EvalPromptSetsUpdateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = EvalApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = EvalApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = EvalApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = EvalApiError404.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = EvalApiError422.from_dict(response.json()) + + return response_422 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError422 + | EvalPromptSetsUpdateResponse +]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, + body: EvalPromptSetsUpdateBody, +) -> Response[ + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError422 + | EvalPromptSetsUpdateResponse +]: + """Update an eval prompt set + + Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully + replaces the existing list — existing prompts omitted from the list are deleted, entries without an + `id` are created, and entries with a matching `id` are updated in place. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + body (EvalPromptSetsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError422 | EvalPromptSetsUpdateResponse] + """ + + kwargs = _get_kwargs( + prompt_set_id=prompt_set_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, + body: EvalPromptSetsUpdateBody, +) -> ( + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError422 + | EvalPromptSetsUpdateResponse + | None +): + """Update an eval prompt set + + Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully + replaces the existing list — existing prompts omitted from the list are deleted, entries without an + `id` are created, and entries with a matching `id` are updated in place. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + body (EvalPromptSetsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError422 | EvalPromptSetsUpdateResponse + """ + + return sync_detailed( + prompt_set_id=prompt_set_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, + body: EvalPromptSetsUpdateBody, +) -> Response[ + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError422 + | EvalPromptSetsUpdateResponse +]: + """Update an eval prompt set + + Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully + replaces the existing list — existing prompts omitted from the list are deleted, entries without an + `id` are created, and entries with a matching `id` are updated in place. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + body (EvalPromptSetsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError422 | EvalPromptSetsUpdateResponse] + """ + + kwargs = _get_kwargs( + prompt_set_id=prompt_set_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + prompt_set_id: UUID, + *, + client: AuthenticatedClient | Client, + body: EvalPromptSetsUpdateBody, +) -> ( + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError422 + | EvalPromptSetsUpdateResponse + | None +): + """Update an eval prompt set + + Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully + replaces the existing list — existing prompts omitted from the list are deleted, entries without an + `id` are created, and entries with a matching `id` are updated in place. + + Args: + prompt_set_id (UUID): The unique identifier of the eval prompt set. Example: + 550e8400-e29b-41d4-a716-446655440000. + body (EvalPromptSetsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError422 | EvalPromptSetsUpdateResponse + """ + + return ( + await asyncio_detailed( + prompt_set_id=prompt_set_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_eval/ai_eval_runs_archive.py b/omni_python_sdk/api/ai_eval/ai_eval_runs_archive.py new file mode 100644 index 0000000..629b02d --- /dev/null +++ b/omni_python_sdk/api/ai_eval/ai_eval_runs_archive.py @@ -0,0 +1,200 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.eval_api_error_401 import EvalApiError401 +from ...models.eval_api_error_403 import EvalApiError403 +from ...models.eval_api_error_404 import EvalApiError404 +from ...models.eval_api_error_500 import EvalApiError500 +from ...models.eval_runs_delete_response import EvalRunsDeleteResponse +from ...types import Response + + +def _get_kwargs( + run_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/ai/eval/runs/{run_id}".format( + run_id=quote(str(run_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsDeleteResponse | None: + if response.status_code == 200: + response_200 = EvalRunsDeleteResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = EvalApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = EvalApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = EvalApiError404.from_dict(response.json()) + + return response_404 + + if response.status_code == 500: + response_500 = EvalApiError500.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsDeleteResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsDeleteResponse]: + """Archive an eval run + + Archive (soft-delete) an eval run. Any non-terminal per-prompt agentic jobs are cancelled as part of + the archive (best-effort), and a still-RUNNING run is flipped to CANCELLED before archival. The call + is idempotent; archiving an already-terminal or already-archived run is a no-op. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsDeleteResponse] + """ + + kwargs = _get_kwargs( + run_id=run_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsDeleteResponse | None: + """Archive an eval run + + Archive (soft-delete) an eval run. Any non-terminal per-prompt agentic jobs are cancelled as part of + the archive (best-effort), and a still-RUNNING run is flipped to CANCELLED before archival. The call + is idempotent; archiving an already-terminal or already-archived run is a no-op. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsDeleteResponse + """ + + return sync_detailed( + run_id=run_id, + client=client, + ).parsed + + +async def asyncio_detailed( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsDeleteResponse]: + """Archive an eval run + + Archive (soft-delete) an eval run. Any non-terminal per-prompt agentic jobs are cancelled as part of + the archive (best-effort), and a still-RUNNING run is flipped to CANCELLED before archival. The call + is idempotent; archiving an already-terminal or already-archived run is a no-op. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsDeleteResponse] + """ + + kwargs = _get_kwargs( + run_id=run_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsDeleteResponse | None: + """Archive an eval run + + Archive (soft-delete) an eval run. Any non-terminal per-prompt agentic jobs are cancelled as part of + the archive (best-effort), and a still-RUNNING run is flipped to CANCELLED before archival. The call + is idempotent; archiving an already-terminal or already-archived run is a no-op. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsDeleteResponse + """ + + return ( + await asyncio_detailed( + run_id=run_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_eval/ai_eval_runs_cancel.py b/omni_python_sdk/api/ai_eval/ai_eval_runs_cancel.py new file mode 100644 index 0000000..9ffa88e --- /dev/null +++ b/omni_python_sdk/api/ai_eval/ai_eval_runs_cancel.py @@ -0,0 +1,200 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.eval_api_error_401 import EvalApiError401 +from ...models.eval_api_error_403 import EvalApiError403 +from ...models.eval_api_error_404 import EvalApiError404 +from ...models.eval_api_error_500 import EvalApiError500 +from ...models.eval_runs_cancel_response import EvalRunsCancelResponse +from ...types import Response + + +def _get_kwargs( + run_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/ai/eval/runs/{run_id}/cancel".format( + run_id=quote(str(run_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsCancelResponse | None: + if response.status_code == 200: + response_200 = EvalRunsCancelResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = EvalApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = EvalApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = EvalApiError404.from_dict(response.json()) + + return response_404 + + if response.status_code == 500: + response_500 = EvalApiError500.from_dict(response.json()) + + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsCancelResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsCancelResponse]: + """Cancel an eval run + + Cancel an in-flight eval run. Any non-terminal per-prompt jobs are cancelled and the run is archived + — the response returns the updated run inline (`status: CANCELLED`, `is_archived: true`); use + `/unarchive` to surface it in the default `archived=false` list again. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsCancelResponse] + """ + + kwargs = _get_kwargs( + run_id=run_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsCancelResponse | None: + """Cancel an eval run + + Cancel an in-flight eval run. Any non-terminal per-prompt jobs are cancelled and the run is archived + — the response returns the updated run inline (`status: CANCELLED`, `is_archived: true`); use + `/unarchive` to surface it in the default `archived=false` list again. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsCancelResponse + """ + + return sync_detailed( + run_id=run_id, + client=client, + ).parsed + + +async def asyncio_detailed( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsCancelResponse]: + """Cancel an eval run + + Cancel an in-flight eval run. Any non-terminal per-prompt jobs are cancelled and the run is archived + — the response returns the updated run inline (`status: CANCELLED`, `is_archived: true`); use + `/unarchive` to surface it in the default `archived=false` list again. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsCancelResponse] + """ + + kwargs = _get_kwargs( + run_id=run_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsCancelResponse | None: + """Cancel an eval run + + Cancel an in-flight eval run. Any non-terminal per-prompt jobs are cancelled and the run is archived + — the response returns the updated run inline (`status: CANCELLED`, `is_archived: true`); use + `/unarchive` to surface it in the default `archived=false` list again. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError500 | EvalRunsCancelResponse + """ + + return ( + await asyncio_detailed( + run_id=run_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_eval/ai_eval_runs_create.py b/omni_python_sdk/api/ai_eval/ai_eval_runs_create.py new file mode 100644 index 0000000..8df66b7 --- /dev/null +++ b/omni_python_sdk/api/ai_eval/ai_eval_runs_create.py @@ -0,0 +1,287 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.eval_api_error_400 import EvalApiError400 +from ...models.eval_api_error_401 import EvalApiError401 +from ...models.eval_api_error_403 import EvalApiError403 +from ...models.eval_api_error_404 import EvalApiError404 +from ...models.eval_api_error_422 import EvalApiError422 +from ...models.eval_api_error_429 import EvalApiError429 +from ...models.eval_api_error_500 import EvalApiError500 +from ...models.eval_api_error_503 import EvalApiError503 +from ...models.eval_runs_create_body import EvalRunsCreateBody +from ...models.eval_runs_create_response import EvalRunsCreateResponse +from ...types import Response + + +def _get_kwargs( + *, + body: EvalRunsCreateBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/ai/eval/runs", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ( + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError422 + | EvalApiError429 + | EvalApiError500 + | EvalApiError503 + | EvalRunsCreateResponse + | None +): + if response.status_code == 201: + response_201 = EvalRunsCreateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = EvalApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = EvalApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = EvalApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = EvalApiError404.from_dict(response.json()) + + return response_404 + + if response.status_code == 422: + response_422 = EvalApiError422.from_dict(response.json()) + + return response_422 + + if response.status_code == 429: + response_429 = EvalApiError429.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = EvalApiError500.from_dict(response.json()) + + return response_500 + + if response.status_code == 503: + response_503 = EvalApiError503.from_dict(response.json()) + + return response_503 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError422 + | EvalApiError429 + | EvalApiError500 + | EvalApiError503 + | EvalRunsCreateResponse +]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: EvalRunsCreateBody, +) -> Response[ + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError422 + | EvalApiError429 + | EvalApiError500 + | EvalApiError503 + | EvalRunsCreateResponse +]: + """Start an eval run + + Create and start a new run against an existing prompt set. The run enqueues one agentic job per + prompt and begins executing immediately. Returns the newly created run with its initial per-prompt + result rows. + + Args: + body (EvalRunsCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError422 | EvalApiError429 | EvalApiError500 | EvalApiError503 | EvalRunsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: EvalRunsCreateBody, +) -> ( + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError422 + | EvalApiError429 + | EvalApiError500 + | EvalApiError503 + | EvalRunsCreateResponse + | None +): + """Start an eval run + + Create and start a new run against an existing prompt set. The run enqueues one agentic job per + prompt and begins executing immediately. Returns the newly created run with its initial per-prompt + result rows. + + Args: + body (EvalRunsCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError422 | EvalApiError429 | EvalApiError500 | EvalApiError503 | EvalRunsCreateResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: EvalRunsCreateBody, +) -> Response[ + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError422 + | EvalApiError429 + | EvalApiError500 + | EvalApiError503 + | EvalRunsCreateResponse +]: + """Start an eval run + + Create and start a new run against an existing prompt set. The run enqueues one agentic job per + prompt and begins executing immediately. Returns the newly created run with its initial per-prompt + result rows. + + Args: + body (EvalRunsCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError422 | EvalApiError429 | EvalApiError500 | EvalApiError503 | EvalRunsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: EvalRunsCreateBody, +) -> ( + EvalApiError400 + | EvalApiError401 + | EvalApiError403 + | EvalApiError404 + | EvalApiError422 + | EvalApiError429 + | EvalApiError500 + | EvalApiError503 + | EvalRunsCreateResponse + | None +): + """Start an eval run + + Create and start a new run against an existing prompt set. The run enqueues one agentic job per + prompt and begins executing immediately. Returns the newly created run with its initial per-prompt + result rows. + + Args: + body (EvalRunsCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalApiError422 | EvalApiError429 | EvalApiError500 | EvalApiError503 | EvalRunsCreateResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_eval/ai_eval_runs_get.py b/omni_python_sdk/api/ai_eval/ai_eval_runs_get.py new file mode 100644 index 0000000..fe0dc46 --- /dev/null +++ b/omni_python_sdk/api/ai_eval/ai_eval_runs_get.py @@ -0,0 +1,190 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.eval_api_error_401 import EvalApiError401 +from ...models.eval_api_error_403 import EvalApiError403 +from ...models.eval_api_error_404 import EvalApiError404 +from ...models.eval_runs_get_response import EvalRunsGetResponse +from ...types import Response + + +def _get_kwargs( + run_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/eval/runs/{run_id}".format( + run_id=quote(str(run_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsGetResponse | None: + if response.status_code == 200: + response_200 = EvalRunsGetResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = EvalApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = EvalApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = EvalApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsGetResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsGetResponse]: + """Get an eval run + + Get an eval run with every per-prompt result row, including the underlying agentic job state and any + scoring data. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsGetResponse] + """ + + kwargs = _get_kwargs( + run_id=run_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsGetResponse | None: + """Get an eval run + + Get an eval run with every per-prompt result row, including the underlying agentic job state and any + scoring data. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsGetResponse + """ + + return sync_detailed( + run_id=run_id, + client=client, + ).parsed + + +async def asyncio_detailed( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsGetResponse]: + """Get an eval run + + Get an eval run with every per-prompt result row, including the underlying agentic job state and any + scoring data. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsGetResponse] + """ + + kwargs = _get_kwargs( + run_id=run_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsGetResponse | None: + """Get an eval run + + Get an eval run with every per-prompt result row, including the underlying agentic job state and any + scoring data. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsGetResponse + """ + + return ( + await asyncio_detailed( + run_id=run_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_eval/ai_eval_runs_list.py b/omni_python_sdk/api/ai_eval/ai_eval_runs_list.py new file mode 100644 index 0000000..6b10140 --- /dev/null +++ b/omni_python_sdk/api/ai_eval/ai_eval_runs_list.py @@ -0,0 +1,226 @@ +from http import HTTPStatus +from typing import Any +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_eval_runs_list_archived import AiEvalRunsListArchived +from ...models.eval_api_error_400 import EvalApiError400 +from ...models.eval_api_error_401 import EvalApiError401 +from ...models.eval_api_error_403 import EvalApiError403 +from ...models.eval_api_error_404 import EvalApiError404 +from ...models.eval_runs_list_response import EvalRunsListResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + archived: AiEvalRunsListArchived | Unset = UNSET, + prompt_set_id: UUID, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_archived: str | Unset = UNSET + if not isinstance(archived, Unset): + json_archived = archived + + params["archived"] = json_archived + + json_prompt_set_id = str(prompt_set_id) + params["prompt_set_id"] = json_prompt_set_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/eval/runs", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsListResponse | None: + if response.status_code == 200: + response_200 = EvalRunsListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = EvalApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = EvalApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = EvalApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = EvalApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + archived: AiEvalRunsListArchived | Unset = UNSET, + prompt_set_id: UUID, +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsListResponse]: + """List eval runs + + List runs for a prompt set, newest first, filtered to runs whose model the caller can access. The + `prompt_set_id` query parameter is required. + + Args: + archived (AiEvalRunsListArchived | Unset): When `true`, returns archived runs instead of + active ones. Defaults to `false`. Example: false. + prompt_set_id (UUID): Required — the prompt set whose runs should be listed. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsListResponse] + """ + + kwargs = _get_kwargs( + archived=archived, + prompt_set_id=prompt_set_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + archived: AiEvalRunsListArchived | Unset = UNSET, + prompt_set_id: UUID, +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsListResponse | None: + """List eval runs + + List runs for a prompt set, newest first, filtered to runs whose model the caller can access. The + `prompt_set_id` query parameter is required. + + Args: + archived (AiEvalRunsListArchived | Unset): When `true`, returns archived runs instead of + active ones. Defaults to `false`. Example: false. + prompt_set_id (UUID): Required — the prompt set whose runs should be listed. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsListResponse + """ + + return sync_detailed( + client=client, + archived=archived, + prompt_set_id=prompt_set_id, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + archived: AiEvalRunsListArchived | Unset = UNSET, + prompt_set_id: UUID, +) -> Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsListResponse]: + """List eval runs + + List runs for a prompt set, newest first, filtered to runs whose model the caller can access. The + `prompt_set_id` query parameter is required. + + Args: + archived (AiEvalRunsListArchived | Unset): When `true`, returns archived runs instead of + active ones. Defaults to `false`. Example: false. + prompt_set_id (UUID): Required — the prompt set whose runs should be listed. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsListResponse] + """ + + kwargs = _get_kwargs( + archived=archived, + prompt_set_id=prompt_set_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + archived: AiEvalRunsListArchived | Unset = UNSET, + prompt_set_id: UUID, +) -> EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsListResponse | None: + """List eval runs + + List runs for a prompt set, newest first, filtered to runs whose model the caller can access. The + `prompt_set_id` query parameter is required. + + Args: + archived (AiEvalRunsListArchived | Unset): When `true`, returns archived runs instead of + active ones. Defaults to `false`. Example: false. + prompt_set_id (UUID): Required — the prompt set whose runs should be listed. Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError400 | EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsListResponse + """ + + return ( + await asyncio_detailed( + client=client, + archived=archived, + prompt_set_id=prompt_set_id, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_eval/ai_eval_runs_unarchive.py b/omni_python_sdk/api/ai_eval/ai_eval_runs_unarchive.py new file mode 100644 index 0000000..1997a35 --- /dev/null +++ b/omni_python_sdk/api/ai_eval/ai_eval_runs_unarchive.py @@ -0,0 +1,186 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.eval_api_error_401 import EvalApiError401 +from ...models.eval_api_error_403 import EvalApiError403 +from ...models.eval_api_error_404 import EvalApiError404 +from ...models.eval_runs_unarchive_response import EvalRunsUnarchiveResponse +from ...types import Response + + +def _get_kwargs( + run_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/ai/eval/runs/{run_id}/unarchive".format( + run_id=quote(str(run_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsUnarchiveResponse | None: + if response.status_code == 200: + response_200 = EvalRunsUnarchiveResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = EvalApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = EvalApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = EvalApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsUnarchiveResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsUnarchiveResponse]: + """Restore an archived eval run + + Restore an archived eval run. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsUnarchiveResponse] + """ + + kwargs = _get_kwargs( + run_id=run_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsUnarchiveResponse | None: + """Restore an archived eval run + + Restore an archived eval run. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsUnarchiveResponse + """ + + return sync_detailed( + run_id=run_id, + client=client, + ).parsed + + +async def asyncio_detailed( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsUnarchiveResponse]: + """Restore an archived eval run + + Restore an archived eval run. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsUnarchiveResponse] + """ + + kwargs = _get_kwargs( + run_id=run_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsUnarchiveResponse | None: + """Restore an archived eval run + + Restore an archived eval run. + + Args: + run_id (UUID): The unique identifier of the eval run. Example: + 660e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + EvalApiError401 | EvalApiError403 | EvalApiError404 | EvalRunsUnarchiveResponse + """ + + return ( + await asyncio_detailed( + run_id=run_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_model_suggestions/__init__.py b/omni_python_sdk/api/ai_model_suggestions/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/ai_model_suggestions/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/ai_model_suggestions/model_suggestions_delete.py b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_delete.py new file mode 100644 index 0000000..6b4b68f --- /dev/null +++ b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_delete.py @@ -0,0 +1,204 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.success_response import SuccessResponse +from ...types import Response + + +def _get_kwargs( + model_id: UUID, + suggestion_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/models/{model_id}/suggestions/{suggestion_id}".format( + model_id=quote(str(model_id), safe=""), + suggestion_id=quote(str(suggestion_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + suggestion_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Delete a suggestion + + Permanently deletes a suggestion. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestion belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + suggestion_id (UUID): UUID of the suggestion Example: + b2c3d4e5-f6a7-8901-bcde-f12345678901. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + suggestion_id=suggestion_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + suggestion_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Delete a suggestion + + Permanently deletes a suggestion. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestion belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + suggestion_id (UUID): UUID of the suggestion Example: + b2c3d4e5-f6a7-8901-bcde-f12345678901. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + suggestion_id=suggestion_id, + client=client, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + suggestion_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Delete a suggestion + + Permanently deletes a suggestion. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestion belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + suggestion_id (UUID): UUID of the suggestion Example: + b2c3d4e5-f6a7-8901-bcde-f12345678901. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + suggestion_id=suggestion_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + suggestion_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Delete a suggestion + + Permanently deletes a suggestion. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestion belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + suggestion_id (UUID): UUID of the suggestion Example: + b2c3d4e5-f6a7-8901-bcde-f12345678901. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + suggestion_id=suggestion_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_model_suggestions/model_suggestions_ignore.py b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_ignore.py new file mode 100644 index 0000000..daaa595 --- /dev/null +++ b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_ignore.py @@ -0,0 +1,226 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ignore_suggestion_body import IgnoreSuggestionBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + suggestion_id: UUID, + *, + body: IgnoreSuggestionBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/suggestions/{suggestion_id}/ignore".format( + model_id=quote(str(model_id), safe=""), + suggestion_id=quote(str(suggestion_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + suggestion_id: UUID, + *, + client: AuthenticatedClient | Client, + body: IgnoreSuggestionBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Ignore a suggestion + + Dismisses (ignores) a suggestion, optionally with a reason. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestion belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + suggestion_id (UUID): UUID of the suggestion Example: + b2c3d4e5-f6a7-8901-bcde-f12345678901. + body (IgnoreSuggestionBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + suggestion_id=suggestion_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + suggestion_id: UUID, + *, + client: AuthenticatedClient | Client, + body: IgnoreSuggestionBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Ignore a suggestion + + Dismisses (ignores) a suggestion, optionally with a reason. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestion belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + suggestion_id (UUID): UUID of the suggestion Example: + b2c3d4e5-f6a7-8901-bcde-f12345678901. + body (IgnoreSuggestionBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + suggestion_id=suggestion_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + suggestion_id: UUID, + *, + client: AuthenticatedClient | Client, + body: IgnoreSuggestionBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Ignore a suggestion + + Dismisses (ignores) a suggestion, optionally with a reason. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestion belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + suggestion_id (UUID): UUID of the suggestion Example: + b2c3d4e5-f6a7-8901-bcde-f12345678901. + body (IgnoreSuggestionBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + suggestion_id=suggestion_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + suggestion_id: UUID, + *, + client: AuthenticatedClient | Client, + body: IgnoreSuggestionBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Ignore a suggestion + + Dismisses (ignores) a suggestion, optionally with a reason. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestion belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + suggestion_id (UUID): UUID of the suggestion Example: + b2c3d4e5-f6a7-8901-bcde-f12345678901. + body (IgnoreSuggestionBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + suggestion_id=suggestion_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_model_suggestions/model_suggestions_list.py b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_list.py new file mode 100644 index 0000000..2f69feb --- /dev/null +++ b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_list.py @@ -0,0 +1,263 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.model_suggestions_list_response import ModelSuggestionsListResponse +from ...models.model_suggestions_list_status import ModelSuggestionsListStatus +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + cursor: UUID | Unset = UNSET, + page_size: int | Unset = 20, + status: ModelSuggestionsListStatus | Unset = "active", +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_cursor: str | Unset = UNSET + if not isinstance(cursor, Unset): + json_cursor = str(cursor) + params["cursor"] = json_cursor + + params["pageSize"] = page_size + + json_status: str | Unset = UNSET + if not isinstance(status, Unset): + json_status = status + + params["status"] = json_status + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/suggestions".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelSuggestionsListResponse | None: + if response.status_code == 200: + response_200 = ModelSuggestionsListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelSuggestionsListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + cursor: UUID | Unset = UNSET, + page_size: int | Unset = 20, + status: ModelSuggestionsListStatus | Unset = "active", +) -> Response[Any | ModelSuggestionsListResponse]: + """List model suggestions + + Lists AI-generated model suggestions for a shared model, filtered by dismissal status. Requires + organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + cursor (UUID | Unset): Cursor for pagination: the `nextCursor` from the previous response + (the last suggestion id). + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + status (ModelSuggestionsListStatus | Unset): Which suggestions to return: `active` + (default, not dismissed), `ignored` (dismissed only), or `all`. Default: 'active'. + Example: active. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelSuggestionsListResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + cursor=cursor, + page_size=page_size, + status=status, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + cursor: UUID | Unset = UNSET, + page_size: int | Unset = 20, + status: ModelSuggestionsListStatus | Unset = "active", +) -> Any | ModelSuggestionsListResponse | None: + """List model suggestions + + Lists AI-generated model suggestions for a shared model, filtered by dismissal status. Requires + organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + cursor (UUID | Unset): Cursor for pagination: the `nextCursor` from the previous response + (the last suggestion id). + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + status (ModelSuggestionsListStatus | Unset): Which suggestions to return: `active` + (default, not dismissed), `ignored` (dismissed only), or `all`. Default: 'active'. + Example: active. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelSuggestionsListResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + cursor=cursor, + page_size=page_size, + status=status, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + cursor: UUID | Unset = UNSET, + page_size: int | Unset = 20, + status: ModelSuggestionsListStatus | Unset = "active", +) -> Response[Any | ModelSuggestionsListResponse]: + """List model suggestions + + Lists AI-generated model suggestions for a shared model, filtered by dismissal status. Requires + organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + cursor (UUID | Unset): Cursor for pagination: the `nextCursor` from the previous response + (the last suggestion id). + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + status (ModelSuggestionsListStatus | Unset): Which suggestions to return: `active` + (default, not dismissed), `ignored` (dismissed only), or `all`. Default: 'active'. + Example: active. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelSuggestionsListResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + cursor=cursor, + page_size=page_size, + status=status, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + cursor: UUID | Unset = UNSET, + page_size: int | Unset = 20, + status: ModelSuggestionsListStatus | Unset = "active", +) -> Any | ModelSuggestionsListResponse | None: + """List model suggestions + + Lists AI-generated model suggestions for a shared model, filtered by dismissal status. Requires + organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + cursor (UUID | Unset): Cursor for pagination: the `nextCursor` from the previous response + (the last suggestion id). + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + status (ModelSuggestionsListStatus | Unset): Which suggestions to return: `active` + (default, not dismissed), `ignored` (dismissed only), or `all`. Default: 'active'. + Example: active. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelSuggestionsListResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + cursor=cursor, + page_size=page_size, + status=status, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_model_suggestions/model_suggestions_restore.py b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_restore.py new file mode 100644 index 0000000..e47a12e --- /dev/null +++ b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_restore.py @@ -0,0 +1,208 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.success_response import SuccessResponse +from ...types import Response + + +def _get_kwargs( + model_id: UUID, + suggestion_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/suggestions/{suggestion_id}/restore".format( + model_id=quote(str(model_id), safe=""), + suggestion_id=quote(str(suggestion_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + suggestion_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Restore a suggestion + + Restores a previously dismissed suggestion back to the active list. Requires organization admin + permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestion belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + suggestion_id (UUID): UUID of the suggestion Example: + b2c3d4e5-f6a7-8901-bcde-f12345678901. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + suggestion_id=suggestion_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + suggestion_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Restore a suggestion + + Restores a previously dismissed suggestion back to the active list. Requires organization admin + permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestion belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + suggestion_id (UUID): UUID of the suggestion Example: + b2c3d4e5-f6a7-8901-bcde-f12345678901. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + suggestion_id=suggestion_id, + client=client, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + suggestion_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Restore a suggestion + + Restores a previously dismissed suggestion back to the active list. Requires organization admin + permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestion belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + suggestion_id (UUID): UUID of the suggestion Example: + b2c3d4e5-f6a7-8901-bcde-f12345678901. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + suggestion_id=suggestion_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + suggestion_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Restore a suggestion + + Restores a previously dismissed suggestion back to the active list. Requires organization admin + permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestion belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + suggestion_id (UUID): UUID of the suggestion Example: + b2c3d4e5-f6a7-8901-bcde-f12345678901. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + suggestion_id=suggestion_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_model_suggestions/model_suggestions_schedule_disable.py b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_schedule_disable.py new file mode 100644 index 0000000..d494f49 --- /dev/null +++ b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_schedule_disable.py @@ -0,0 +1,190 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.success_response import SuccessResponse +from ...types import Response + + +def _get_kwargs( + model_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/models/{model_id}/suggestions/schedule".format( + model_id=quote(str(model_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Disable the suggestion schedule + + Disables the daily generation schedule for the shared model. Idempotent. Requires organization admin + permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Disable the suggestion schedule + + Disables the daily generation schedule for the shared model. Idempotent. Requires organization admin + permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Disable the suggestion schedule + + Disables the daily generation schedule for the shared model. Idempotent. Requires organization admin + permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Disable the suggestion schedule + + Disables the daily generation schedule for the shared model. Idempotent. Requires organization admin + permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_model_suggestions/model_suggestions_schedule_enable.py b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_schedule_enable.py new file mode 100644 index 0000000..98a9741 --- /dev/null +++ b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_schedule_enable.py @@ -0,0 +1,214 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.schedule_suggestions_body import ScheduleSuggestionsBody +from ...models.schedule_suggestions_response import ScheduleSuggestionsResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + body: ScheduleSuggestionsBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/models/{model_id}/suggestions/schedule".format( + model_id=quote(str(model_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ScheduleSuggestionsResponse | None: + if response.status_code == 200: + response_200 = ScheduleSuggestionsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScheduleSuggestionsResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ScheduleSuggestionsBody | Unset = UNSET, +) -> Response[Any | ScheduleSuggestionsResponse]: + """Enable the suggestion schedule + + Enables the daily schedule that generates suggestions for the shared model. Idempotent — re-enabling + leaves an existing schedule untouched. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + body (ScheduleSuggestionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScheduleSuggestionsResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ScheduleSuggestionsBody | Unset = UNSET, +) -> Any | ScheduleSuggestionsResponse | None: + """Enable the suggestion schedule + + Enables the daily schedule that generates suggestions for the shared model. Idempotent — re-enabling + leaves an existing schedule untouched. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + body (ScheduleSuggestionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScheduleSuggestionsResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ScheduleSuggestionsBody | Unset = UNSET, +) -> Response[Any | ScheduleSuggestionsResponse]: + """Enable the suggestion schedule + + Enables the daily schedule that generates suggestions for the shared model. Idempotent — re-enabling + leaves an existing schedule untouched. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + body (ScheduleSuggestionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScheduleSuggestionsResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ScheduleSuggestionsBody | Unset = UNSET, +) -> Any | ScheduleSuggestionsResponse | None: + """Enable the suggestion schedule + + Enables the daily schedule that generates suggestions for the shared model. Idempotent — re-enabling + leaves an existing schedule untouched. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + body (ScheduleSuggestionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScheduleSuggestionsResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_routines/__init__.py b/omni_python_sdk/api/ai_routines/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/ai_routines/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/ai_routines/routine_create.py b/omni_python_sdk/api/ai_routines/routine_create.py new file mode 100644 index 0000000..bf8af54 --- /dev/null +++ b/omni_python_sdk/api/ai_routines/routine_create.py @@ -0,0 +1,238 @@ +from http import HTTPStatus +from typing import Any +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...models.api_error_429 import ApiError429 +from ...models.routine_create_body import RoutineCreateBody +from ...models.routine_create_response import RoutineCreateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: RoutineCreateBody, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/ai/routines", + "params": params, + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError429 | RoutineCreateResponse | None: + if response.status_code == 201: + response_201 = RoutineCreateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if response.status_code == 429: + response_429 = ApiError429.from_dict(response.json()) + + return response_429 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError429 | RoutineCreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: RoutineCreateBody, + user_id: UUID | Unset = UNSET, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError429 | RoutineCreateResponse]: + """Create a routine + + Create a routine that runs a saved prompt on a schedule and delivers the AI response through a + single destination — email (one or more recipients / user groups) or Slack (a single channel or + direct message). Each scheduled run executes once using the routine owner's permissions, and every + recipient receives the same result. Organization API keys can pass `?userId=` to + create the routine for a specific organization member. + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (RoutineCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError429 | RoutineCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: RoutineCreateBody, + user_id: UUID | Unset = UNSET, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError429 | RoutineCreateResponse | None: + """Create a routine + + Create a routine that runs a saved prompt on a schedule and delivers the AI response through a + single destination — email (one or more recipients / user groups) or Slack (a single channel or + direct message). Each scheduled run executes once using the routine owner's permissions, and every + recipient receives the same result. Organization API keys can pass `?userId=` to + create the routine for a specific organization member. + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (RoutineCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError429 | RoutineCreateResponse + """ + + return sync_detailed( + client=client, + body=body, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: RoutineCreateBody, + user_id: UUID | Unset = UNSET, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError429 | RoutineCreateResponse]: + """Create a routine + + Create a routine that runs a saved prompt on a schedule and delivers the AI response through a + single destination — email (one or more recipients / user groups) or Slack (a single channel or + direct message). Each scheduled run executes once using the routine owner's permissions, and every + recipient receives the same result. Organization API keys can pass `?userId=` to + create the routine for a specific organization member. + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (RoutineCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError429 | RoutineCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: RoutineCreateBody, + user_id: UUID | Unset = UNSET, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError429 | RoutineCreateResponse | None: + """Create a routine + + Create a routine that runs a saved prompt on a schedule and delivers the AI response through a + single destination — email (one or more recipients / user groups) or Slack (a single channel or + direct message). Each scheduled run executes once using the routine owner's permissions, and every + recipient receives the same result. Organization API keys can pass `?userId=` to + create the routine for a specific organization member. + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (RoutineCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError429 | RoutineCreateResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_routines/routine_delete.py b/omni_python_sdk/api/ai_routines/routine_delete.py new file mode 100644 index 0000000..2632a3f --- /dev/null +++ b/omni_python_sdk/api/ai_routines/routine_delete.py @@ -0,0 +1,212 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...models.routine_delete_response import RoutineDeleteResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: UUID, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/ai/routines/{id}".format( + id=quote(str(id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineDeleteResponse | None: + if response.status_code == 200: + response_200 = RoutineDeleteResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineDeleteResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineDeleteResponse]: + """Delete a routine + + Delete a routine. It stops running immediately and no longer appears in list or get responses. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineDeleteResponse] + """ + + kwargs = _get_kwargs( + id=id, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineDeleteResponse | None: + """Delete a routine + + Delete a routine. It stops running immediately and no longer appears in list or get responses. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineDeleteResponse + """ + + return sync_detailed( + id=id, + client=client, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineDeleteResponse]: + """Delete a routine + + Delete a routine. It stops running immediately and no longer appears in list or get responses. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineDeleteResponse] + """ + + kwargs = _get_kwargs( + id=id, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineDeleteResponse | None: + """Delete a routine + + Delete a routine. It stops running immediately and no longer appears in list or get responses. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineDeleteResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_routines/routine_get.py b/omni_python_sdk/api/ai_routines/routine_get.py new file mode 100644 index 0000000..9d5d5db --- /dev/null +++ b/omni_python_sdk/api/ai_routines/routine_get.py @@ -0,0 +1,212 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...models.routine_response import RoutineResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: UUID, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/routines/{id}".format( + id=quote(str(id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse | None: + if response.status_code == 200: + response_200 = RoutineResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse]: + """Get a routine + + Get a single routine, including the status of its most recent completed run. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse] + """ + + kwargs = _get_kwargs( + id=id, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse | None: + """Get a routine + + Get a single routine, including the status of its most recent completed run. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse + """ + + return sync_detailed( + id=id, + client=client, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse]: + """Get a routine + + Get a single routine, including the status of its most recent completed run. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse] + """ + + kwargs = _get_kwargs( + id=id, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse | None: + """Get a routine + + Get a single routine, including the status of its most recent completed run. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_routines/routine_trigger.py b/omni_python_sdk/api/ai_routines/routine_trigger.py new file mode 100644 index 0000000..95ed257 --- /dev/null +++ b/omni_python_sdk/api/ai_routines/routine_trigger.py @@ -0,0 +1,230 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...models.api_error_409 import ApiError409 +from ...models.routine_trigger_response import RoutineTriggerResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: UUID, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/ai/routines/{id}/trigger".format( + id=quote(str(id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | RoutineTriggerResponse | None: + if response.status_code == 202: + response_202 = RoutineTriggerResponse.from_dict(response.json()) + + return response_202 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if response.status_code == 409: + response_409 = ApiError409.from_dict(response.json()) + + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | RoutineTriggerResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | RoutineTriggerResponse]: + """Run a routine now + + Run a routine immediately, in addition to its schedule. The run executes once using the routine + owner's permissions and delivers the AI response to every configured recipient — it is not a private + preview. Returns once the run has started; the result is delivered asynchronously. Organization API + keys can pass `?userId=` to act on behalf of a specific organization member. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | RoutineTriggerResponse] + """ + + kwargs = _get_kwargs( + id=id, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | RoutineTriggerResponse | None: + """Run a routine now + + Run a routine immediately, in addition to its schedule. The run executes once using the routine + owner's permissions and delivers the AI response to every configured recipient — it is not a private + preview. Returns once the run has started; the result is delivered asynchronously. Organization API + keys can pass `?userId=` to act on behalf of a specific organization member. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | RoutineTriggerResponse + """ + + return sync_detailed( + id=id, + client=client, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | RoutineTriggerResponse]: + """Run a routine now + + Run a routine immediately, in addition to its schedule. The run executes once using the routine + owner's permissions and delivers the AI response to every configured recipient — it is not a private + preview. Returns once the run has started; the result is delivered asynchronously. Organization API + keys can pass `?userId=` to act on behalf of a specific organization member. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | RoutineTriggerResponse] + """ + + kwargs = _get_kwargs( + id=id, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | RoutineTriggerResponse | None: + """Run a routine now + + Run a routine immediately, in addition to its schedule. The run executes once using the routine + owner's permissions and delivers the AI response to every configured recipient — it is not a private + preview. Returns once the run has started; the result is delivered asynchronously. Organization API + keys can pass `?userId=` to act on behalf of a specific organization member. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | ApiError409 | RoutineTriggerResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_routines/routine_update.py b/omni_python_sdk/api/ai_routines/routine_update.py new file mode 100644 index 0000000..b624fba --- /dev/null +++ b/omni_python_sdk/api/ai_routines/routine_update.py @@ -0,0 +1,236 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...models.routine_response import RoutineResponse +from ...models.routine_update_body import RoutineUpdateBody +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: UUID, + *, + body: RoutineUpdateBody, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/ai/routines/{id}".format( + id=quote(str(id), safe=""), + ), + "params": params, + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse | None: + if response.status_code == 200: + response_200 = RoutineResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: RoutineUpdateBody, + user_id: UUID | Unset = UNSET, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse]: + """Update a routine + + Update a routine. All request fields are optional, and only supplied fields are changed. Supplying + `destination` replaces the full recipient configuration. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (RoutineUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: RoutineUpdateBody, + user_id: UUID | Unset = UNSET, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse | None: + """Update a routine + + Update a routine. All request fields are optional, and only supplied fields are changed. Supplying + `destination` replaces the full recipient configuration. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (RoutineUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse + """ + + return sync_detailed( + id=id, + client=client, + body=body, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: RoutineUpdateBody, + user_id: UUID | Unset = UNSET, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse]: + """Update a routine + + Update a routine. All request fields are optional, and only supplied fields are changed. Supplying + `destination` replaces the full recipient configuration. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (RoutineUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: RoutineUpdateBody, + user_id: UUID | Unset = UNSET, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse | None: + """Update a routine + + Update a routine. All request fields are optional, and only supplied fields are changed. Supplying + `destination` replaces the full recipient configuration. + + Args: + id (UUID): The UUID of the routine. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (RoutineUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutineResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_routines/routines_list.py b/omni_python_sdk/api/ai_routines/routines_list.py new file mode 100644 index 0000000..6e170b0 --- /dev/null +++ b/omni_python_sdk/api/ai_routines/routines_list.py @@ -0,0 +1,285 @@ +from http import HTTPStatus +from typing import Any +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...models.routines_list_response import RoutinesListResponse +from ...models.routines_list_sort_direction import RoutinesListSortDirection +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: RoutinesListSortDirection | Unset = "desc", + sort_field: str | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["pageSize"] = page_size + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + params["sortField"] = sort_field + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/routines", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutinesListResponse | None: + if response.status_code == 200: + response_200 = RoutinesListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutinesListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: RoutinesListSortDirection | Unset = "desc", + sort_field: str | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutinesListResponse]: + """List routines + + List routines for the calling user, newest first. Includes routines paused by the owner or disabled + by Omni, but excludes deleted routines. Use `pageInfo.nextCursor` from one response as the `cursor` + query parameter on the next request. Organization API keys can pass `?userId=` to list + routines for a specific organization member. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (RoutinesListSortDirection | Unset): Sort direction for results Default: + 'desc'. Example: desc. + sort_field (str | Unset): Field to sort results by + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutinesListResponse] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: RoutinesListSortDirection | Unset = "desc", + sort_field: str | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutinesListResponse | None: + """List routines + + List routines for the calling user, newest first. Includes routines paused by the owner or disabled + by Omni, but excludes deleted routines. Use `pageInfo.nextCursor` from one response as the `cursor` + query parameter on the next request. Organization API keys can pass `?userId=` to list + routines for a specific organization member. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (RoutinesListSortDirection | Unset): Sort direction for results Default: + 'desc'. Example: desc. + sort_field (str | Unset): Field to sort results by + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutinesListResponse + """ + + return sync_detailed( + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: RoutinesListSortDirection | Unset = "desc", + sort_field: str | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutinesListResponse]: + """List routines + + List routines for the calling user, newest first. Includes routines paused by the owner or disabled + by Omni, but excludes deleted routines. Use `pageInfo.nextCursor` from one response as the `cursor` + query parameter on the next request. Organization API keys can pass `?userId=` to list + routines for a specific organization member. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (RoutinesListSortDirection | Unset): Sort direction for results Default: + 'desc'. Example: desc. + sort_field (str | Unset): Field to sort results by + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutinesListResponse] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: RoutinesListSortDirection | Unset = "desc", + sort_field: str | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutinesListResponse | None: + """List routines + + List routines for the calling user, newest first. Includes routines paused by the owner or disabled + by Omni, but excludes deleted routines. Use `pageInfo.nextCursor` from one response as the `cursor` + query parameter on the next request. Organization API keys can pass `?userId=` to list + routines for a specific organization member. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (RoutinesListSortDirection | Unset): Sort direction for results Default: + 'desc'. Example: desc. + sort_field (str | Unset): Field to sort results by + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + ApiError400 | ApiError401 | ApiError403 | ApiError404 | RoutinesListResponse + """ + + return ( + await asyncio_detailed( + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/api_tokens/__init__.py b/omni_python_sdk/api/api_tokens/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/api_tokens/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/api_tokens/api_keys_delete.py b/omni_python_sdk/api/api_tokens/api_keys_delete.py new file mode 100644 index 0000000..a191d41 --- /dev/null +++ b/omni_python_sdk/api/api_tokens/api_keys_delete.py @@ -0,0 +1,184 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.api_key_delete_response import ApiKeyDeleteResponse +from ...types import Response + + +def _get_kwargs( + id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/api-keys/{id}".format( + id=quote(str(id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ApiKeyDeleteResponse | None: + if response.status_code == 200: + response_200 = ApiKeyDeleteResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ApiKeyDeleteResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ApiKeyDeleteResponse]: + """Revoke an API token + + Revokes an API token by permanently deleting it. Works for all token types. Requires organization + admin permissions. + + Args: + id (UUID): Token UUID Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ApiKeyDeleteResponse] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ApiKeyDeleteResponse | None: + """Revoke an API token + + Revokes an API token by permanently deleting it. Works for all token types. Requires organization + admin permissions. + + Args: + id (UUID): Token UUID Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ApiKeyDeleteResponse + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ApiKeyDeleteResponse]: + """Revoke an API token + + Revokes an API token by permanently deleting it. Works for all token types. Requires organization + admin permissions. + + Args: + id (UUID): Token UUID Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ApiKeyDeleteResponse] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ApiKeyDeleteResponse | None: + """Revoke an API token + + Revokes an API token by permanently deleting it. Works for all token types. Requires organization + admin permissions. + + Args: + id (UUID): Token UUID Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ApiKeyDeleteResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/api_tokens/api_keys_get.py b/omni_python_sdk/api/api_tokens/api_keys_get.py new file mode 100644 index 0000000..29aae61 --- /dev/null +++ b/omni_python_sdk/api/api_tokens/api_keys_get.py @@ -0,0 +1,176 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.api_key import ApiKey +from ...types import Response + + +def _get_kwargs( + id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/api-keys/{id}".format( + id=quote(str(id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | ApiKey | None: + if response.status_code == 200: + response_200 = ApiKey.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | ApiKey]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ApiKey]: + """Get API token + + Returns a single API token by id. Requires organization admin permissions. + + Args: + id (UUID): Token UUID Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ApiKey] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ApiKey | None: + """Get API token + + Returns a single API token by id. Requires organization admin permissions. + + Args: + id (UUID): Token UUID Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ApiKey + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ApiKey]: + """Get API token + + Returns a single API token by id. Requires organization admin permissions. + + Args: + id (UUID): Token UUID Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ApiKey] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ApiKey | None: + """Get API token + + Returns a single API token by id. Requires organization admin permissions. + + Args: + id (UUID): Token UUID Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ApiKey + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/api_tokens/api_keys_list.py b/omni_python_sdk/api/api_tokens/api_keys_list.py new file mode 100644 index 0000000..775615c --- /dev/null +++ b/omni_python_sdk/api/api_tokens/api_keys_list.py @@ -0,0 +1,275 @@ +from http import HTTPStatus +from typing import Any, cast +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.api_key_list_response import ApiKeyListResponse +from ...models.api_keys_list_sort_direction import ApiKeysListSortDirection +from ...models.api_keys_list_sort_field import ApiKeysListSortField +from ...models.api_keys_list_type import ApiKeysListType +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + cursor: UUID | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ApiKeysListSortDirection | Unset = "desc", + sort_field: ApiKeysListSortField | Unset = "createdAt", + type_: ApiKeysListType | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_cursor: str | Unset = UNSET + if not isinstance(cursor, Unset): + json_cursor = str(cursor) + params["cursor"] = json_cursor + + params["pageSize"] = page_size + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + json_sort_field: str | Unset = UNSET + if not isinstance(sort_field, Unset): + json_sort_field = sort_field + + params["sortField"] = json_sort_field + + json_type_: str | Unset = UNSET + if not isinstance(type_, Unset): + json_type_ = type_ + + params["type"] = json_type_ + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/api-keys", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ApiKeyListResponse | None: + if response.status_code == 200: + response_200 = ApiKeyListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ApiKeyListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + cursor: UUID | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ApiKeysListSortDirection | Unset = "desc", + sort_field: ApiKeysListSortField | Unset = "createdAt", + type_: ApiKeysListType | Unset = UNSET, +) -> Response[Any | ApiKeyListResponse]: + """List API tokens + + Returns all API tokens in the organization, including organization-level keys, personal access + tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions. + + Args: + cursor (UUID | Unset): Cursor from the previous response (token UUID) + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (ApiKeysListSortDirection | Unset): Sort direction for results Default: + 'desc'. Example: desc. + sort_field (ApiKeysListSortField | Unset): Default: 'createdAt'. + type_ (ApiKeysListType | Unset): Filter by API token type. When omitted, all types are + returned. Example: personal. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ApiKeyListResponse] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + type_=type_, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + cursor: UUID | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ApiKeysListSortDirection | Unset = "desc", + sort_field: ApiKeysListSortField | Unset = "createdAt", + type_: ApiKeysListType | Unset = UNSET, +) -> Any | ApiKeyListResponse | None: + """List API tokens + + Returns all API tokens in the organization, including organization-level keys, personal access + tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions. + + Args: + cursor (UUID | Unset): Cursor from the previous response (token UUID) + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (ApiKeysListSortDirection | Unset): Sort direction for results Default: + 'desc'. Example: desc. + sort_field (ApiKeysListSortField | Unset): Default: 'createdAt'. + type_ (ApiKeysListType | Unset): Filter by API token type. When omitted, all types are + returned. Example: personal. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ApiKeyListResponse + """ + + return sync_detailed( + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + type_=type_, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + cursor: UUID | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ApiKeysListSortDirection | Unset = "desc", + sort_field: ApiKeysListSortField | Unset = "createdAt", + type_: ApiKeysListType | Unset = UNSET, +) -> Response[Any | ApiKeyListResponse]: + """List API tokens + + Returns all API tokens in the organization, including organization-level keys, personal access + tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions. + + Args: + cursor (UUID | Unset): Cursor from the previous response (token UUID) + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (ApiKeysListSortDirection | Unset): Sort direction for results Default: + 'desc'. Example: desc. + sort_field (ApiKeysListSortField | Unset): Default: 'createdAt'. + type_ (ApiKeysListType | Unset): Filter by API token type. When omitted, all types are + returned. Example: personal. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ApiKeyListResponse] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + type_=type_, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + cursor: UUID | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ApiKeysListSortDirection | Unset = "desc", + sort_field: ApiKeysListSortField | Unset = "createdAt", + type_: ApiKeysListType | Unset = UNSET, +) -> Any | ApiKeyListResponse | None: + """List API tokens + + Returns all API tokens in the organization, including organization-level keys, personal access + tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions. + + Args: + cursor (UUID | Unset): Cursor from the previous response (token UUID) + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (ApiKeysListSortDirection | Unset): Sort direction for results Default: + 'desc'. Example: desc. + sort_field (ApiKeysListSortField | Unset): Default: 'createdAt'. + type_ (ApiKeysListType | Unset): Filter by API token type. When omitted, all types are + returned. Example: personal. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ApiKeyListResponse + """ + + return ( + await asyncio_detailed( + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + type_=type_, + ) + ).parsed diff --git a/omni_python_sdk/api/api_tokens/api_keys_update.py b/omni_python_sdk/api/api_tokens/api_keys_update.py new file mode 100644 index 0000000..3b17330 --- /dev/null +++ b/omni_python_sdk/api/api_tokens/api_keys_update.py @@ -0,0 +1,197 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.api_key import ApiKey +from ...models.api_key_update_body import ApiKeyUpdateBody +from ...types import Response + + +def _get_kwargs( + id: UUID, + *, + body: ApiKeyUpdateBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/api-keys/{id}".format( + id=quote(str(id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | ApiKey | None: + if response.status_code == 200: + response_200 = ApiKey.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | ApiKey]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ApiKeyUpdateBody, +) -> Response[Any | ApiKey]: + """Enable or disable an API token + + Enables or disables an API token. Requires organization admin permissions. + + Args: + id (UUID): Token UUID Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + body (ApiKeyUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ApiKey] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ApiKeyUpdateBody, +) -> Any | ApiKey | None: + """Enable or disable an API token + + Enables or disables an API token. Requires organization admin permissions. + + Args: + id (UUID): Token UUID Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + body (ApiKeyUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ApiKey + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ApiKeyUpdateBody, +) -> Response[Any | ApiKey]: + """Enable or disable an API token + + Enables or disables an API token. Requires organization admin permissions. + + Args: + id (UUID): Token UUID Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + body (ApiKeyUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ApiKey] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ApiKeyUpdateBody, +) -> Any | ApiKey | None: + """Enable or disable an API token + + Enables or disables an API token. Requires organization admin permissions. + + Args: + id (UUID): Token UUID Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + body (ApiKeyUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ApiKey + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/__init__.py b/omni_python_sdk/api/connections/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/connections/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/connections/connection_environments_create.py b/omni_python_sdk/api/connections/connection_environments_create.py new file mode 100644 index 0000000..c5d7a7e --- /dev/null +++ b/omni_python_sdk/api/connections/connection_environments_create.py @@ -0,0 +1,185 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connection_environments_create_connections_environments_create_body import ( + ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody, +) +from ...models.connection_environments_create_connections_environments_create_response import ( + ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse, +) +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/connection-environments", + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse | None: + if response.status_code == 201: + response_201 = ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody | Unset = UNSET, +) -> Response[Any | ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse]: + """Create connection environments + + Args: + body (ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody | Unset): Request body + for creating connection environments + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody | Unset = UNSET, +) -> Any | ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse | None: + """Create connection environments + + Args: + body (ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody | Unset): Request body + for creating connection environments + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody | Unset = UNSET, +) -> Response[Any | ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse]: + """Create connection environments + + Args: + body (ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody | Unset): Request body + for creating connection environments + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody | Unset = UNSET, +) -> Any | ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse | None: + """Create connection environments + + Args: + body (ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody | Unset): Request body + for creating connection environments + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connection_environments_delete.py b/omni_python_sdk/api/connections/connection_environments_delete.py new file mode 100644 index 0000000..4e565bf --- /dev/null +++ b/omni_python_sdk/api/connections/connection_environments_delete.py @@ -0,0 +1,170 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connection_environments_delete_connections_environments_delete_response import ( + ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse, +) +from ...types import Response + + +def _get_kwargs( + id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/connection-environments/{id}".format( + id=quote(str(id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse | None: + if response.status_code == 200: + response_200 = ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse]: + """Delete connection environment + + Args: + id (UUID): Connection environment ID Example: 550e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse | None: + """Delete connection environment + + Args: + id (UUID): Connection environment ID Example: 550e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse]: + """Delete connection environment + + Args: + id (UUID): Connection environment ID Example: 550e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse | None: + """Delete connection environment + + Args: + id (UUID): Connection environment ID Example: 550e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connection_environments_update.py b/omni_python_sdk/api/connections/connection_environments_update.py new file mode 100644 index 0000000..460d140 --- /dev/null +++ b/omni_python_sdk/api/connections/connection_environments_update.py @@ -0,0 +1,202 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connection_environments_update_connections_environments_update_body import ( + ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody, +) +from ...models.connection_environments_update_connections_environments_update_response import ( + ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse, +) +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: UUID, + *, + body: ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/connection-environments/{id}".format( + id=quote(str(id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse | None: + if response.status_code == 200: + response_200 = ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody | Unset = UNSET, +) -> Response[Any | ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse]: + """Update connection environment + + Args: + id (UUID): Connection environment ID Example: 550e8400-e29b-41d4-a716-446655440001. + body (ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody | Unset): Request body + for updating a connection environment + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody | Unset = UNSET, +) -> Any | ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse | None: + """Update connection environment + + Args: + id (UUID): Connection environment ID Example: 550e8400-e29b-41d4-a716-446655440001. + body (ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody | Unset): Request body + for updating a connection environment + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody | Unset = UNSET, +) -> Response[Any | ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse]: + """Update connection environment + + Args: + id (UUID): Connection environment ID Example: 550e8400-e29b-41d4-a716-446655440001. + body (ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody | Unset): Request body + for updating a connection environment + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody | Unset = UNSET, +) -> Any | ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse | None: + """Update connection environment + + Args: + id (UUID): Connection environment ID Example: 550e8400-e29b-41d4-a716-446655440001. + body (ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody | Unset): Request body + for updating a connection environment + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_create.py b/omni_python_sdk/api/connections/connections_create.py new file mode 100644 index 0000000..f017bee --- /dev/null +++ b/omni_python_sdk/api/connections/connections_create.py @@ -0,0 +1,193 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_create_connections_create_body import ConnectionsCreateConnectionsCreateBody +from ...models.connections_create_connections_create_response import ConnectionsCreateConnectionsCreateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: ConnectionsCreateConnectionsCreateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/connections", + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsCreateConnectionsCreateResponse | None: + if response.status_code == 201: + response_201 = ConnectionsCreateConnectionsCreateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsCreateConnectionsCreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: ConnectionsCreateConnectionsCreateBody | Unset = UNSET, +) -> Response[Any | ConnectionsCreateConnectionsCreateResponse]: + """Create connection + + Create a new database connection. The request body varies by dialect - see dialect-specific + documentation for required fields. + + Args: + body (ConnectionsCreateConnectionsCreateBody | Unset): Request body for creating a + database connection. Required fields: dialect, name, passwordUnencrypted. Additional + fields may be required depending on the dialect. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsCreateConnectionsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: ConnectionsCreateConnectionsCreateBody | Unset = UNSET, +) -> Any | ConnectionsCreateConnectionsCreateResponse | None: + """Create connection + + Create a new database connection. The request body varies by dialect - see dialect-specific + documentation for required fields. + + Args: + body (ConnectionsCreateConnectionsCreateBody | Unset): Request body for creating a + database connection. Required fields: dialect, name, passwordUnencrypted. Additional + fields may be required depending on the dialect. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsCreateConnectionsCreateResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: ConnectionsCreateConnectionsCreateBody | Unset = UNSET, +) -> Response[Any | ConnectionsCreateConnectionsCreateResponse]: + """Create connection + + Create a new database connection. The request body varies by dialect - see dialect-specific + documentation for required fields. + + Args: + body (ConnectionsCreateConnectionsCreateBody | Unset): Request body for creating a + database connection. Required fields: dialect, name, passwordUnencrypted. Additional + fields may be required depending on the dialect. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsCreateConnectionsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: ConnectionsCreateConnectionsCreateBody | Unset = UNSET, +) -> Any | ConnectionsCreateConnectionsCreateResponse | None: + """Create connection + + Create a new database connection. The request body varies by dialect - see dialect-specific + documentation for required fields. + + Args: + body (ConnectionsCreateConnectionsCreateBody | Unset): Request body for creating a + database connection. Required fields: dialect, name, passwordUnencrypted. Additional + fields may be required depending on the dialect. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsCreateConnectionsCreateResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_dbt_delete.py b/omni_python_sdk/api/connections/connections_dbt_delete.py new file mode 100644 index 0000000..55afa69 --- /dev/null +++ b/omni_python_sdk/api/connections/connections_dbt_delete.py @@ -0,0 +1,170 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_dbt_delete_connections_dbt_delete_response import ( + ConnectionsDbtDeleteConnectionsDbtDeleteResponse, +) +from ...types import Response + + +def _get_kwargs( + connection_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/connections/{connection_id}/dbt".format( + connection_id=quote(str(connection_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsDbtDeleteConnectionsDbtDeleteResponse | None: + if response.status_code == 200: + response_200 = ConnectionsDbtDeleteConnectionsDbtDeleteResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsDbtDeleteConnectionsDbtDeleteResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsDbtDeleteConnectionsDbtDeleteResponse]: + """Delete dbt configuration + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsDbtDeleteConnectionsDbtDeleteResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsDbtDeleteConnectionsDbtDeleteResponse | None: + """Delete dbt configuration + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsDbtDeleteConnectionsDbtDeleteResponse + """ + + return sync_detailed( + connection_id=connection_id, + client=client, + ).parsed + + +async def asyncio_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsDbtDeleteConnectionsDbtDeleteResponse]: + """Delete dbt configuration + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsDbtDeleteConnectionsDbtDeleteResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsDbtDeleteConnectionsDbtDeleteResponse | None: + """Delete dbt configuration + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsDbtDeleteConnectionsDbtDeleteResponse + """ + + return ( + await asyncio_detailed( + connection_id=connection_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_dbt_environments_create.py b/omni_python_sdk/api/connections/connections_dbt_environments_create.py new file mode 100644 index 0000000..4f6d4ce --- /dev/null +++ b/omni_python_sdk/api/connections/connections_dbt_environments_create.py @@ -0,0 +1,201 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.dbt_environment_create_body import DbtEnvironmentCreateBody +from ...models.dbt_environment_item import DbtEnvironmentItem +from ...types import Response + + +def _get_kwargs( + connection_id: UUID, + *, + body: DbtEnvironmentCreateBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/connections/{connection_id}/dbt/environments".format( + connection_id=quote(str(connection_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DbtEnvironmentItem | None: + if response.status_code == 201: + response_201 = DbtEnvironmentItem.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DbtEnvironmentItem]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + body: DbtEnvironmentCreateBody, +) -> Response[Any | DbtEnvironmentItem]: + """Create dbt environment + + Create a new dbt environment for a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (DbtEnvironmentCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DbtEnvironmentItem] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + body: DbtEnvironmentCreateBody, +) -> Any | DbtEnvironmentItem | None: + """Create dbt environment + + Create a new dbt environment for a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (DbtEnvironmentCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DbtEnvironmentItem + """ + + return sync_detailed( + connection_id=connection_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + body: DbtEnvironmentCreateBody, +) -> Response[Any | DbtEnvironmentItem]: + """Create dbt environment + + Create a new dbt environment for a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (DbtEnvironmentCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DbtEnvironmentItem] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + body: DbtEnvironmentCreateBody, +) -> Any | DbtEnvironmentItem | None: + """Create dbt environment + + Create a new dbt environment for a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (DbtEnvironmentCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DbtEnvironmentItem + """ + + return ( + await asyncio_detailed( + connection_id=connection_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_dbt_environments_delete.py b/omni_python_sdk/api/connections/connections_dbt_environments_delete.py new file mode 100644 index 0000000..8fa931b --- /dev/null +++ b/omni_python_sdk/api/connections/connections_dbt_environments_delete.py @@ -0,0 +1,190 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.dbt_environment_delete_response import DbtEnvironmentDeleteResponse +from ...types import Response + + +def _get_kwargs( + connection_id: UUID, + environment_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/connections/{connection_id}/dbt/environments/{environment_id}".format( + connection_id=quote(str(connection_id), safe=""), + environment_id=quote(str(environment_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DbtEnvironmentDeleteResponse | None: + if response.status_code == 200: + response_200 = DbtEnvironmentDeleteResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DbtEnvironmentDeleteResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + connection_id: UUID, + environment_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | DbtEnvironmentDeleteResponse]: + """Delete dbt environment + + Delete a dbt environment from a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + environment_id (UUID): Environment ID Example: 247dc6dc-2a58-4688-9521-c5ed3e99c1e8. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DbtEnvironmentDeleteResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + environment_id=environment_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + connection_id: UUID, + environment_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | DbtEnvironmentDeleteResponse | None: + """Delete dbt environment + + Delete a dbt environment from a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + environment_id (UUID): Environment ID Example: 247dc6dc-2a58-4688-9521-c5ed3e99c1e8. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DbtEnvironmentDeleteResponse + """ + + return sync_detailed( + connection_id=connection_id, + environment_id=environment_id, + client=client, + ).parsed + + +async def asyncio_detailed( + connection_id: UUID, + environment_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | DbtEnvironmentDeleteResponse]: + """Delete dbt environment + + Delete a dbt environment from a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + environment_id (UUID): Environment ID Example: 247dc6dc-2a58-4688-9521-c5ed3e99c1e8. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DbtEnvironmentDeleteResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + environment_id=environment_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + connection_id: UUID, + environment_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | DbtEnvironmentDeleteResponse | None: + """Delete dbt environment + + Delete a dbt environment from a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + environment_id (UUID): Environment ID Example: 247dc6dc-2a58-4688-9521-c5ed3e99c1e8. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DbtEnvironmentDeleteResponse + """ + + return ( + await asyncio_detailed( + connection_id=connection_id, + environment_id=environment_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_dbt_environments_list.py b/omni_python_sdk/api/connections/connections_dbt_environments_list.py new file mode 100644 index 0000000..6922c3a --- /dev/null +++ b/omni_python_sdk/api/connections/connections_dbt_environments_list.py @@ -0,0 +1,272 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_dbt_environments_list_sort_direction import ( + ConnectionsDbtEnvironmentsListSortDirection, +) +from ...models.connections_dbt_environments_list_sort_field import ( + ConnectionsDbtEnvironmentsListSortField, +) +from ...models.dbt_environment_list_response import DbtEnvironmentListResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + connection_id: UUID, + *, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ConnectionsDbtEnvironmentsListSortDirection | Unset = "desc", + sort_field: ConnectionsDbtEnvironmentsListSortField | Unset = "name", +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["pageSize"] = page_size + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + json_sort_field: str | Unset = UNSET + if not isinstance(sort_field, Unset): + json_sort_field = sort_field + + params["sortField"] = json_sort_field + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/connections/{connection_id}/dbt/environments".format( + connection_id=quote(str(connection_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DbtEnvironmentListResponse | None: + if response.status_code == 200: + response_200 = DbtEnvironmentListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DbtEnvironmentListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ConnectionsDbtEnvironmentsListSortDirection | Unset = "desc", + sort_field: ConnectionsDbtEnvironmentsListSortField | Unset = "name", +) -> Response[Any | DbtEnvironmentListResponse]: + """List dbt environments + + List all dbt environments for a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (ConnectionsDbtEnvironmentsListSortDirection | Unset): Sort direction for + results Default: 'desc'. Example: desc. + sort_field (ConnectionsDbtEnvironmentsListSortField | Unset): Field to sort results by + Default: 'name'. Example: name. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DbtEnvironmentListResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ConnectionsDbtEnvironmentsListSortDirection | Unset = "desc", + sort_field: ConnectionsDbtEnvironmentsListSortField | Unset = "name", +) -> Any | DbtEnvironmentListResponse | None: + """List dbt environments + + List all dbt environments for a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (ConnectionsDbtEnvironmentsListSortDirection | Unset): Sort direction for + results Default: 'desc'. Example: desc. + sort_field (ConnectionsDbtEnvironmentsListSortField | Unset): Field to sort results by + Default: 'name'. Example: name. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DbtEnvironmentListResponse + """ + + return sync_detailed( + connection_id=connection_id, + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + ).parsed + + +async def asyncio_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ConnectionsDbtEnvironmentsListSortDirection | Unset = "desc", + sort_field: ConnectionsDbtEnvironmentsListSortField | Unset = "name", +) -> Response[Any | DbtEnvironmentListResponse]: + """List dbt environments + + List all dbt environments for a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (ConnectionsDbtEnvironmentsListSortDirection | Unset): Sort direction for + results Default: 'desc'. Example: desc. + sort_field (ConnectionsDbtEnvironmentsListSortField | Unset): Field to sort results by + Default: 'name'. Example: name. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DbtEnvironmentListResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ConnectionsDbtEnvironmentsListSortDirection | Unset = "desc", + sort_field: ConnectionsDbtEnvironmentsListSortField | Unset = "name", +) -> Any | DbtEnvironmentListResponse | None: + """List dbt environments + + List all dbt environments for a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (ConnectionsDbtEnvironmentsListSortDirection | Unset): Sort direction for + results Default: 'desc'. Example: desc. + sort_field (ConnectionsDbtEnvironmentsListSortField | Unset): Field to sort results by + Default: 'name'. Example: name. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DbtEnvironmentListResponse + """ + + return ( + await asyncio_detailed( + connection_id=connection_id, + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_dbt_environments_update.py b/omni_python_sdk/api/connections/connections_dbt_environments_update.py new file mode 100644 index 0000000..7d8542d --- /dev/null +++ b/omni_python_sdk/api/connections/connections_dbt_environments_update.py @@ -0,0 +1,215 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.dbt_environment_item import DbtEnvironmentItem +from ...models.dbt_environment_update_body import DbtEnvironmentUpdateBody +from ...types import Response + + +def _get_kwargs( + connection_id: UUID, + environment_id: UUID, + *, + body: DbtEnvironmentUpdateBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/connections/{connection_id}/dbt/environments/{environment_id}".format( + connection_id=quote(str(connection_id), safe=""), + environment_id=quote(str(environment_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DbtEnvironmentItem | None: + if response.status_code == 200: + response_200 = DbtEnvironmentItem.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DbtEnvironmentItem]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + connection_id: UUID, + environment_id: UUID, + *, + client: AuthenticatedClient | Client, + body: DbtEnvironmentUpdateBody, +) -> Response[Any | DbtEnvironmentItem]: + """Update dbt environment + + Update an existing dbt environment for a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + environment_id (UUID): Environment ID Example: 247dc6dc-2a58-4688-9521-c5ed3e99c1e8. + body (DbtEnvironmentUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DbtEnvironmentItem] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + environment_id=environment_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + connection_id: UUID, + environment_id: UUID, + *, + client: AuthenticatedClient | Client, + body: DbtEnvironmentUpdateBody, +) -> Any | DbtEnvironmentItem | None: + """Update dbt environment + + Update an existing dbt environment for a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + environment_id (UUID): Environment ID Example: 247dc6dc-2a58-4688-9521-c5ed3e99c1e8. + body (DbtEnvironmentUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DbtEnvironmentItem + """ + + return sync_detailed( + connection_id=connection_id, + environment_id=environment_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + connection_id: UUID, + environment_id: UUID, + *, + client: AuthenticatedClient | Client, + body: DbtEnvironmentUpdateBody, +) -> Response[Any | DbtEnvironmentItem]: + """Update dbt environment + + Update an existing dbt environment for a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + environment_id (UUID): Environment ID Example: 247dc6dc-2a58-4688-9521-c5ed3e99c1e8. + body (DbtEnvironmentUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DbtEnvironmentItem] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + environment_id=environment_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + connection_id: UUID, + environment_id: UUID, + *, + client: AuthenticatedClient | Client, + body: DbtEnvironmentUpdateBody, +) -> Any | DbtEnvironmentItem | None: + """Update dbt environment + + Update an existing dbt environment for a connection. + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + environment_id (UUID): Environment ID Example: 247dc6dc-2a58-4688-9521-c5ed3e99c1e8. + body (DbtEnvironmentUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DbtEnvironmentItem + """ + + return ( + await asyncio_detailed( + connection_id=connection_id, + environment_id=environment_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_dbt_get.py b/omni_python_sdk/api/connections/connections_dbt_get.py new file mode 100644 index 0000000..8e14386 --- /dev/null +++ b/omni_python_sdk/api/connections/connections_dbt_get.py @@ -0,0 +1,187 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_dbt_get_dbt_configured_response import ConnectionsDbtGetDbtConfiguredResponse +from ...models.connections_dbt_get_dbt_not_configured_response import ConnectionsDbtGetDbtNotConfiguredResponse +from ...types import Response + + +def _get_kwargs( + connection_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/connections/{connection_id}/dbt".format( + connection_id=quote(str(connection_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsDbtGetDbtConfiguredResponse | ConnectionsDbtGetDbtNotConfiguredResponse | None: + if response.status_code == 200: + + def _parse_response_200( + data: object, + ) -> ConnectionsDbtGetDbtConfiguredResponse | ConnectionsDbtGetDbtNotConfiguredResponse: + try: + if not isinstance(data, dict): + raise TypeError() + response_200_dbt_configured_response = ConnectionsDbtGetDbtConfiguredResponse.from_dict(data) + + return response_200_dbt_configured_response + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + response_200_dbt_not_configured_response = ConnectionsDbtGetDbtNotConfiguredResponse.from_dict(data) + + return response_200_dbt_not_configured_response + + response_200 = _parse_response_200(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsDbtGetDbtConfiguredResponse | ConnectionsDbtGetDbtNotConfiguredResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsDbtGetDbtConfiguredResponse | ConnectionsDbtGetDbtNotConfiguredResponse]: + """Get dbt configuration + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsDbtGetDbtConfiguredResponse | ConnectionsDbtGetDbtNotConfiguredResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsDbtGetDbtConfiguredResponse | ConnectionsDbtGetDbtNotConfiguredResponse | None: + """Get dbt configuration + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsDbtGetDbtConfiguredResponse | ConnectionsDbtGetDbtNotConfiguredResponse + """ + + return sync_detailed( + connection_id=connection_id, + client=client, + ).parsed + + +async def asyncio_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsDbtGetDbtConfiguredResponse | ConnectionsDbtGetDbtNotConfiguredResponse]: + """Get dbt configuration + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsDbtGetDbtConfiguredResponse | ConnectionsDbtGetDbtNotConfiguredResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsDbtGetDbtConfiguredResponse | ConnectionsDbtGetDbtNotConfiguredResponse | None: + """Get dbt configuration + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsDbtGetDbtConfiguredResponse | ConnectionsDbtGetDbtNotConfiguredResponse + """ + + return ( + await asyncio_detailed( + connection_id=connection_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_dbt_update.py b/omni_python_sdk/api/connections/connections_dbt_update.py new file mode 100644 index 0000000..1efaeb3 --- /dev/null +++ b/omni_python_sdk/api/connections/connections_dbt_update.py @@ -0,0 +1,196 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_dbt_update_connections_dbt_update_body import ConnectionsDbtUpdateConnectionsDbtUpdateBody +from ...models.connections_dbt_update_connections_dbt_update_response import ( + ConnectionsDbtUpdateConnectionsDbtUpdateResponse, +) +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + connection_id: UUID, + *, + body: ConnectionsDbtUpdateConnectionsDbtUpdateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/connections/{connection_id}/dbt".format( + connection_id=quote(str(connection_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsDbtUpdateConnectionsDbtUpdateResponse | None: + if response.status_code == 200: + response_200 = ConnectionsDbtUpdateConnectionsDbtUpdateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsDbtUpdateConnectionsDbtUpdateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsDbtUpdateConnectionsDbtUpdateBody | Unset = UNSET, +) -> Response[Any | ConnectionsDbtUpdateConnectionsDbtUpdateResponse]: + """Update dbt configuration + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ConnectionsDbtUpdateConnectionsDbtUpdateBody | Unset): dbt repository configuration + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsDbtUpdateConnectionsDbtUpdateResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsDbtUpdateConnectionsDbtUpdateBody | Unset = UNSET, +) -> Any | ConnectionsDbtUpdateConnectionsDbtUpdateResponse | None: + """Update dbt configuration + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ConnectionsDbtUpdateConnectionsDbtUpdateBody | Unset): dbt repository configuration + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsDbtUpdateConnectionsDbtUpdateResponse + """ + + return sync_detailed( + connection_id=connection_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsDbtUpdateConnectionsDbtUpdateBody | Unset = UNSET, +) -> Response[Any | ConnectionsDbtUpdateConnectionsDbtUpdateResponse]: + """Update dbt configuration + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ConnectionsDbtUpdateConnectionsDbtUpdateBody | Unset): dbt repository configuration + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsDbtUpdateConnectionsDbtUpdateResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsDbtUpdateConnectionsDbtUpdateBody | Unset = UNSET, +) -> Any | ConnectionsDbtUpdateConnectionsDbtUpdateResponse | None: + """Update dbt configuration + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ConnectionsDbtUpdateConnectionsDbtUpdateBody | Unset): dbt repository configuration + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsDbtUpdateConnectionsDbtUpdateResponse + """ + + return ( + await asyncio_detailed( + connection_id=connection_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_delete.py b/omni_python_sdk/api/connections/connections_delete.py new file mode 100644 index 0000000..22850e3 --- /dev/null +++ b/omni_python_sdk/api/connections/connections_delete.py @@ -0,0 +1,192 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_delete_connections_delete_response import ConnectionsDeleteConnectionsDeleteResponse +from ...types import Response + + +def _get_kwargs( + id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/connections/{id}".format( + id=quote(str(id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsDeleteConnectionsDeleteResponse | None: + if response.status_code == 200: + response_200 = ConnectionsDeleteConnectionsDeleteResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 410: + response_410 = cast(Any, None) + return response_410 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsDeleteConnectionsDeleteResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsDeleteConnectionsDeleteResponse]: + """Delete connection + + Archive a connection (move to trash). Archived connections can be restored from the trash in the + connection settings UI. + + A connection that is already archived returns 410. + + Args: + id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsDeleteConnectionsDeleteResponse] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsDeleteConnectionsDeleteResponse | None: + """Delete connection + + Archive a connection (move to trash). Archived connections can be restored from the trash in the + connection settings UI. + + A connection that is already archived returns 410. + + Args: + id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsDeleteConnectionsDeleteResponse + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsDeleteConnectionsDeleteResponse]: + """Delete connection + + Archive a connection (move to trash). Archived connections can be restored from the trash in the + connection settings UI. + + A connection that is already archived returns 410. + + Args: + id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsDeleteConnectionsDeleteResponse] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsDeleteConnectionsDeleteResponse | None: + """Delete connection + + Archive a connection (move to trash). Archived connections can be restored from the trash in the + connection settings UI. + + A connection that is already archived returns 410. + + Args: + id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsDeleteConnectionsDeleteResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_get.py b/omni_python_sdk/api/connections/connections_get.py new file mode 100644 index 0000000..0cf62cb --- /dev/null +++ b/omni_python_sdk/api/connections/connections_get.py @@ -0,0 +1,176 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_get_connections_get_response import ConnectionsGetConnectionsGetResponse +from ...types import Response + + +def _get_kwargs( + id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/connections/{id}".format( + id=quote(str(id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsGetConnectionsGetResponse | None: + if response.status_code == 200: + response_200 = ConnectionsGetConnectionsGetResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsGetConnectionsGetResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsGetConnectionsGetResponse]: + """Get connection + + Fetch a single connection by ID. + + Args: + id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsGetConnectionsGetResponse] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsGetConnectionsGetResponse | None: + """Get connection + + Fetch a single connection by ID. + + Args: + id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsGetConnectionsGetResponse + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsGetConnectionsGetResponse]: + """Get connection + + Fetch a single connection by ID. + + Args: + id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsGetConnectionsGetResponse] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsGetConnectionsGetResponse | None: + """Get connection + + Fetch a single connection by ID. + + Args: + id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsGetConnectionsGetResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_list.py b/omni_python_sdk/api/connections/connections_list.py new file mode 100644 index 0000000..e208786 --- /dev/null +++ b/omni_python_sdk/api/connections/connections_list.py @@ -0,0 +1,267 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_list_connections_list_response import ConnectionsListConnectionsListResponse +from ...models.connections_list_sort_direction import ( + ConnectionsListSortDirection, +) +from ...models.connections_list_sort_field import ConnectionsListSortField +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + database: str | Unset = UNSET, + dialect: str | Unset = UNSET, + include_deleted: bool | Unset = UNSET, + name: str | Unset = UNSET, + sort_direction: ConnectionsListSortDirection | Unset = UNSET, + sort_field: ConnectionsListSortField | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["database"] = database + + params["dialect"] = dialect + + params["includeDeleted"] = include_deleted + + params["name"] = name + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + json_sort_field: str | Unset = UNSET + if not isinstance(sort_field, Unset): + json_sort_field = sort_field + + params["sortField"] = json_sort_field + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/connections", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsListConnectionsListResponse | None: + if response.status_code == 200: + response_200 = ConnectionsListConnectionsListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsListConnectionsListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + database: str | Unset = UNSET, + dialect: str | Unset = UNSET, + include_deleted: bool | Unset = UNSET, + name: str | Unset = UNSET, + sort_direction: ConnectionsListSortDirection | Unset = UNSET, + sort_field: ConnectionsListSortField | Unset = UNSET, +) -> Response[Any | ConnectionsListConnectionsListResponse]: + """List connections + + Args: + database (str | Unset): Filter by database name (case-insensitive contains) Example: + analytics. + dialect (str | Unset): Filter by dialect(s). Comma-separated list for multiple values + Example: snowflake,bigquery. + include_deleted (bool | Unset): Include soft-deleted connections in results + name (str | Unset): Filter by connection name (case-insensitive contains) Example: + Production. + sort_direction (ConnectionsListSortDirection | Unset): Sort direction Example: desc. + sort_field (ConnectionsListSortField | Unset): Field to sort by Example: name. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsListConnectionsListResponse] + """ + + kwargs = _get_kwargs( + database=database, + dialect=dialect, + include_deleted=include_deleted, + name=name, + sort_direction=sort_direction, + sort_field=sort_field, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + database: str | Unset = UNSET, + dialect: str | Unset = UNSET, + include_deleted: bool | Unset = UNSET, + name: str | Unset = UNSET, + sort_direction: ConnectionsListSortDirection | Unset = UNSET, + sort_field: ConnectionsListSortField | Unset = UNSET, +) -> Any | ConnectionsListConnectionsListResponse | None: + """List connections + + Args: + database (str | Unset): Filter by database name (case-insensitive contains) Example: + analytics. + dialect (str | Unset): Filter by dialect(s). Comma-separated list for multiple values + Example: snowflake,bigquery. + include_deleted (bool | Unset): Include soft-deleted connections in results + name (str | Unset): Filter by connection name (case-insensitive contains) Example: + Production. + sort_direction (ConnectionsListSortDirection | Unset): Sort direction Example: desc. + sort_field (ConnectionsListSortField | Unset): Field to sort by Example: name. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsListConnectionsListResponse + """ + + return sync_detailed( + client=client, + database=database, + dialect=dialect, + include_deleted=include_deleted, + name=name, + sort_direction=sort_direction, + sort_field=sort_field, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + database: str | Unset = UNSET, + dialect: str | Unset = UNSET, + include_deleted: bool | Unset = UNSET, + name: str | Unset = UNSET, + sort_direction: ConnectionsListSortDirection | Unset = UNSET, + sort_field: ConnectionsListSortField | Unset = UNSET, +) -> Response[Any | ConnectionsListConnectionsListResponse]: + """List connections + + Args: + database (str | Unset): Filter by database name (case-insensitive contains) Example: + analytics. + dialect (str | Unset): Filter by dialect(s). Comma-separated list for multiple values + Example: snowflake,bigquery. + include_deleted (bool | Unset): Include soft-deleted connections in results + name (str | Unset): Filter by connection name (case-insensitive contains) Example: + Production. + sort_direction (ConnectionsListSortDirection | Unset): Sort direction Example: desc. + sort_field (ConnectionsListSortField | Unset): Field to sort by Example: name. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsListConnectionsListResponse] + """ + + kwargs = _get_kwargs( + database=database, + dialect=dialect, + include_deleted=include_deleted, + name=name, + sort_direction=sort_direction, + sort_field=sort_field, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + database: str | Unset = UNSET, + dialect: str | Unset = UNSET, + include_deleted: bool | Unset = UNSET, + name: str | Unset = UNSET, + sort_direction: ConnectionsListSortDirection | Unset = UNSET, + sort_field: ConnectionsListSortField | Unset = UNSET, +) -> Any | ConnectionsListConnectionsListResponse | None: + """List connections + + Args: + database (str | Unset): Filter by database name (case-insensitive contains) Example: + analytics. + dialect (str | Unset): Filter by dialect(s). Comma-separated list for multiple values + Example: snowflake,bigquery. + include_deleted (bool | Unset): Include soft-deleted connections in results + name (str | Unset): Filter by connection name (case-insensitive contains) Example: + Production. + sort_direction (ConnectionsListSortDirection | Unset): Sort direction Example: desc. + sort_field (ConnectionsListSortField | Unset): Field to sort by Example: name. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsListConnectionsListResponse + """ + + return ( + await asyncio_detailed( + client=client, + database=database, + dialect=dialect, + include_deleted=include_deleted, + name=name, + sort_direction=sort_direction, + sort_field=sort_field, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_schedules_create.py b/omni_python_sdk/api/connections/connections_schedules_create.py new file mode 100644 index 0000000..12b8a22 --- /dev/null +++ b/omni_python_sdk/api/connections/connections_schedules_create.py @@ -0,0 +1,202 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_schedules_create_connections_schedules_create_body import ( + ConnectionsSchedulesCreateConnectionsSchedulesCreateBody, +) +from ...models.connections_schedules_create_connections_schedules_create_response import ( + ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse, +) +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + connection_id: UUID, + *, + body: ConnectionsSchedulesCreateConnectionsSchedulesCreateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/connections/{connection_id}/schedules".format( + connection_id=quote(str(connection_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse | None: + if response.status_code == 201: + response_201 = ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsSchedulesCreateConnectionsSchedulesCreateBody | Unset = UNSET, +) -> Response[Any | ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse]: + """Create schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ConnectionsSchedulesCreateConnectionsSchedulesCreateBody | Unset): Request body for + creating a schema refresh schedule + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsSchedulesCreateConnectionsSchedulesCreateBody | Unset = UNSET, +) -> Any | ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse | None: + """Create schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ConnectionsSchedulesCreateConnectionsSchedulesCreateBody | Unset): Request body for + creating a schema refresh schedule + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse + """ + + return sync_detailed( + connection_id=connection_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsSchedulesCreateConnectionsSchedulesCreateBody | Unset = UNSET, +) -> Response[Any | ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse]: + """Create schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ConnectionsSchedulesCreateConnectionsSchedulesCreateBody | Unset): Request body for + creating a schema refresh schedule + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsSchedulesCreateConnectionsSchedulesCreateBody | Unset = UNSET, +) -> Any | ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse | None: + """Create schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ConnectionsSchedulesCreateConnectionsSchedulesCreateBody | Unset): Request body for + creating a schema refresh schedule + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse + """ + + return ( + await asyncio_detailed( + connection_id=connection_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_schedules_delete.py b/omni_python_sdk/api/connections/connections_schedules_delete.py new file mode 100644 index 0000000..45b76c1 --- /dev/null +++ b/omni_python_sdk/api/connections/connections_schedules_delete.py @@ -0,0 +1,184 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_schedules_delete_connections_schedules_delete_response import ( + ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse, +) +from ...types import Response + + +def _get_kwargs( + connection_id: UUID, + schedule_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/connections/{connection_id}/schedules/{schedule_id}".format( + connection_id=quote(str(connection_id), safe=""), + schedule_id=quote(str(schedule_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse | None: + if response.status_code == 200: + response_200 = ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + connection_id: UUID, + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse]: + """Delete schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + schedule_id (UUID): Schedule ID Example: 550e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + schedule_id=schedule_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + connection_id: UUID, + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse | None: + """Delete schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + schedule_id (UUID): Schedule ID Example: 550e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse + """ + + return sync_detailed( + connection_id=connection_id, + schedule_id=schedule_id, + client=client, + ).parsed + + +async def asyncio_detailed( + connection_id: UUID, + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse]: + """Delete schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + schedule_id (UUID): Schedule ID Example: 550e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + schedule_id=schedule_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + connection_id: UUID, + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse | None: + """Delete schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + schedule_id (UUID): Schedule ID Example: 550e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse + """ + + return ( + await asyncio_detailed( + connection_id=connection_id, + schedule_id=schedule_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_schedules_get.py b/omni_python_sdk/api/connections/connections_schedules_get.py new file mode 100644 index 0000000..3305053 --- /dev/null +++ b/omni_python_sdk/api/connections/connections_schedules_get.py @@ -0,0 +1,184 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_schedules_get_connections_schedules_get_response import ( + ConnectionsSchedulesGetConnectionsSchedulesGetResponse, +) +from ...types import Response + + +def _get_kwargs( + connection_id: UUID, + schedule_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/connections/{connection_id}/schedules/{schedule_id}".format( + connection_id=quote(str(connection_id), safe=""), + schedule_id=quote(str(schedule_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsSchedulesGetConnectionsSchedulesGetResponse | None: + if response.status_code == 200: + response_200 = ConnectionsSchedulesGetConnectionsSchedulesGetResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsSchedulesGetConnectionsSchedulesGetResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + connection_id: UUID, + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsSchedulesGetConnectionsSchedulesGetResponse]: + """Get schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + schedule_id (UUID): Schedule ID Example: 550e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsSchedulesGetConnectionsSchedulesGetResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + schedule_id=schedule_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + connection_id: UUID, + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsSchedulesGetConnectionsSchedulesGetResponse | None: + """Get schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + schedule_id (UUID): Schedule ID Example: 550e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsSchedulesGetConnectionsSchedulesGetResponse + """ + + return sync_detailed( + connection_id=connection_id, + schedule_id=schedule_id, + client=client, + ).parsed + + +async def asyncio_detailed( + connection_id: UUID, + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsSchedulesGetConnectionsSchedulesGetResponse]: + """Get schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + schedule_id (UUID): Schedule ID Example: 550e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsSchedulesGetConnectionsSchedulesGetResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + schedule_id=schedule_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + connection_id: UUID, + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsSchedulesGetConnectionsSchedulesGetResponse | None: + """Get schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + schedule_id (UUID): Schedule ID Example: 550e8400-e29b-41d4-a716-446655440001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsSchedulesGetConnectionsSchedulesGetResponse + """ + + return ( + await asyncio_detailed( + connection_id=connection_id, + schedule_id=schedule_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_schedules_list.py b/omni_python_sdk/api/connections/connections_schedules_list.py new file mode 100644 index 0000000..348f6f7 --- /dev/null +++ b/omni_python_sdk/api/connections/connections_schedules_list.py @@ -0,0 +1,170 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_schedules_list_connections_schedules_list_response import ( + ConnectionsSchedulesListConnectionsSchedulesListResponse, +) +from ...types import Response + + +def _get_kwargs( + connection_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/connections/{connection_id}/schedules".format( + connection_id=quote(str(connection_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsSchedulesListConnectionsSchedulesListResponse | None: + if response.status_code == 200: + response_200 = ConnectionsSchedulesListConnectionsSchedulesListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsSchedulesListConnectionsSchedulesListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsSchedulesListConnectionsSchedulesListResponse]: + """List schema refresh schedules + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsSchedulesListConnectionsSchedulesListResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsSchedulesListConnectionsSchedulesListResponse | None: + """List schema refresh schedules + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsSchedulesListConnectionsSchedulesListResponse + """ + + return sync_detailed( + connection_id=connection_id, + client=client, + ).parsed + + +async def asyncio_detailed( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ConnectionsSchedulesListConnectionsSchedulesListResponse]: + """List schema refresh schedules + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsSchedulesListConnectionsSchedulesListResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + connection_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ConnectionsSchedulesListConnectionsSchedulesListResponse | None: + """List schema refresh schedules + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsSchedulesListConnectionsSchedulesListResponse + """ + + return ( + await asyncio_detailed( + connection_id=connection_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_schedules_update.py b/omni_python_sdk/api/connections/connections_schedules_update.py new file mode 100644 index 0000000..dc57a64 --- /dev/null +++ b/omni_python_sdk/api/connections/connections_schedules_update.py @@ -0,0 +1,216 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_schedules_update_connections_schedules_update_body import ( + ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody, +) +from ...models.connections_schedules_update_connections_schedules_update_response import ( + ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse, +) +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + connection_id: UUID, + schedule_id: UUID, + *, + body: ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/connections/{connection_id}/schedules/{schedule_id}".format( + connection_id=quote(str(connection_id), safe=""), + schedule_id=quote(str(schedule_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse | None: + if response.status_code == 200: + response_200 = ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + connection_id: UUID, + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody | Unset = UNSET, +) -> Response[Any | ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse]: + """Update schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + schedule_id (UUID): Schedule ID Example: 550e8400-e29b-41d4-a716-446655440001. + body (ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody | Unset): Request body for + updating a schema refresh schedule + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + schedule_id=schedule_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + connection_id: UUID, + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody | Unset = UNSET, +) -> Any | ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse | None: + """Update schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + schedule_id (UUID): Schedule ID Example: 550e8400-e29b-41d4-a716-446655440001. + body (ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody | Unset): Request body for + updating a schema refresh schedule + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse + """ + + return sync_detailed( + connection_id=connection_id, + schedule_id=schedule_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + connection_id: UUID, + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody | Unset = UNSET, +) -> Response[Any | ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse]: + """Update schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + schedule_id (UUID): Schedule ID Example: 550e8400-e29b-41d4-a716-446655440001. + body (ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody | Unset): Request body for + updating a schema refresh schedule + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse] + """ + + kwargs = _get_kwargs( + connection_id=connection_id, + schedule_id=schedule_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + connection_id: UUID, + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody | Unset = UNSET, +) -> Any | ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse | None: + """Update schema refresh schedule + + Args: + connection_id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + schedule_id (UUID): Schedule ID Example: 550e8400-e29b-41d4-a716-446655440001. + body (ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody | Unset): Request body for + updating a schema refresh schedule + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse + """ + + return ( + await asyncio_detailed( + connection_id=connection_id, + schedule_id=schedule_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/connections/connections_update.py b/omni_python_sdk/api/connections/connections_update.py new file mode 100644 index 0000000..839feb6 --- /dev/null +++ b/omni_python_sdk/api/connections/connections_update.py @@ -0,0 +1,230 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.connections_update_connections_update_body import ConnectionsUpdateConnectionsUpdateBody +from ...models.connections_update_connections_update_response import ConnectionsUpdateConnectionsUpdateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: UUID, + *, + body: ConnectionsUpdateConnectionsUpdateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/connections/{id}".format( + id=quote(str(id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ConnectionsUpdateConnectionsUpdateResponse | None: + if response.status_code == 200: + response_200 = ConnectionsUpdateConnectionsUpdateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ConnectionsUpdateConnectionsUpdateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsUpdateConnectionsUpdateBody | Unset = UNSET, +) -> Response[Any | ConnectionsUpdateConnectionsUpdateResponse]: + """Update connection + + Update connection settings including base role, environment user attributes, and credentials. + + Credential fields: + - `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery) + - `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication + + Note: Credentials are encrypted at rest and never returned in API responses. + + Args: + id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ConnectionsUpdateConnectionsUpdateBody | Unset): Request body for updating + connection attributes and credentials. At least one field must be provided. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsUpdateConnectionsUpdateResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsUpdateConnectionsUpdateBody | Unset = UNSET, +) -> Any | ConnectionsUpdateConnectionsUpdateResponse | None: + """Update connection + + Update connection settings including base role, environment user attributes, and credentials. + + Credential fields: + - `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery) + - `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication + + Note: Credentials are encrypted at rest and never returned in API responses. + + Args: + id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ConnectionsUpdateConnectionsUpdateBody | Unset): Request body for updating + connection attributes and credentials. At least one field must be provided. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsUpdateConnectionsUpdateResponse + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsUpdateConnectionsUpdateBody | Unset = UNSET, +) -> Response[Any | ConnectionsUpdateConnectionsUpdateResponse]: + """Update connection + + Update connection settings including base role, environment user attributes, and credentials. + + Credential fields: + - `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery) + - `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication + + Note: Credentials are encrypted at rest and never returned in API responses. + + Args: + id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ConnectionsUpdateConnectionsUpdateBody | Unset): Request body for updating + connection attributes and credentials. At least one field must be provided. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ConnectionsUpdateConnectionsUpdateResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ConnectionsUpdateConnectionsUpdateBody | Unset = UNSET, +) -> Any | ConnectionsUpdateConnectionsUpdateResponse | None: + """Update connection + + Update connection settings including base role, environment user attributes, and credentials. + + Credential fields: + - `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery) + - `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication + + Note: Credentials are encrypted at rest and never returned in API responses. + + Args: + id (UUID): Connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ConnectionsUpdateConnectionsUpdateBody | Unset): Request body for updating + connection attributes and credentials. At least one field must be provided. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ConnectionsUpdateConnectionsUpdateResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/content/__init__.py b/omni_python_sdk/api/content/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/content/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/content/content_list.py b/omni_python_sdk/api/content/content_list.py new file mode 100644 index 0000000..b00434d --- /dev/null +++ b/omni_python_sdk/api/content/content_list.py @@ -0,0 +1,326 @@ +from http import HTTPStatus +from typing import Any, cast +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.content_list_response import ContentListResponse +from ...models.content_list_scope import ContentListScope +from ...models.content_list_sort_direction import ContentListSortDirection +from ...models.content_list_sort_field import ContentListSortField +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + creator_id: UUID | Unset = UNSET, + folder_id: UUID | Unset = UNSET, + include: str | Unset = UNSET, + path: str | Unset = UNSET, + scope: ContentListScope | Unset = UNSET, + sort_direction: ContentListSortDirection | Unset = UNSET, + sort_field: ContentListSortField | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["pageSize"] = page_size + + json_creator_id: str | Unset = UNSET + if not isinstance(creator_id, Unset): + json_creator_id = str(creator_id) + params["creatorId"] = json_creator_id + + json_folder_id: str | Unset = UNSET + if not isinstance(folder_id, Unset): + json_folder_id = str(folder_id) + params["folderId"] = json_folder_id + + params["include"] = include + + params["path"] = path + + json_scope: str | Unset = UNSET + if not isinstance(scope, Unset): + json_scope = scope + + params["scope"] = json_scope + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + json_sort_field: str | Unset = UNSET + if not isinstance(sort_field, Unset): + json_sort_field = sort_field + + params["sortField"] = json_sort_field + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/content", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ContentListResponse | None: + if response.status_code == 200: + response_200 = ContentListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ContentListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + creator_id: UUID | Unset = UNSET, + folder_id: UUID | Unset = UNSET, + include: str | Unset = UNSET, + path: str | Unset = UNSET, + scope: ContentListScope | Unset = UNSET, + sort_direction: ContentListSortDirection | Unset = UNSET, + sort_field: ContentListSortField | Unset = UNSET, +) -> Response[Any | ContentListResponse]: + """List content + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + creator_id (UUID | Unset): Filter by creator user ID + folder_id (UUID | Unset): Filter by folder ID (cannot be used with path) + include (str | Unset): Comma-separated list of fields to include (e.g., _count,labels) + path (str | Unset): Filter by folder path (cannot be used with folderId) Example: + /reports/sales. + scope (ContentListScope | Unset): Filter by share scope Example: organization. + sort_direction (ContentListSortDirection | Unset): Sort direction Example: asc. + sort_field (ContentListSortField | Unset): Field to sort by Example: name. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ContentListResponse] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + creator_id=creator_id, + folder_id=folder_id, + include=include, + path=path, + scope=scope, + sort_direction=sort_direction, + sort_field=sort_field, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + creator_id: UUID | Unset = UNSET, + folder_id: UUID | Unset = UNSET, + include: str | Unset = UNSET, + path: str | Unset = UNSET, + scope: ContentListScope | Unset = UNSET, + sort_direction: ContentListSortDirection | Unset = UNSET, + sort_field: ContentListSortField | Unset = UNSET, +) -> Any | ContentListResponse | None: + """List content + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + creator_id (UUID | Unset): Filter by creator user ID + folder_id (UUID | Unset): Filter by folder ID (cannot be used with path) + include (str | Unset): Comma-separated list of fields to include (e.g., _count,labels) + path (str | Unset): Filter by folder path (cannot be used with folderId) Example: + /reports/sales. + scope (ContentListScope | Unset): Filter by share scope Example: organization. + sort_direction (ContentListSortDirection | Unset): Sort direction Example: asc. + sort_field (ContentListSortField | Unset): Field to sort by Example: name. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ContentListResponse + """ + + return sync_detailed( + client=client, + cursor=cursor, + page_size=page_size, + creator_id=creator_id, + folder_id=folder_id, + include=include, + path=path, + scope=scope, + sort_direction=sort_direction, + sort_field=sort_field, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + creator_id: UUID | Unset = UNSET, + folder_id: UUID | Unset = UNSET, + include: str | Unset = UNSET, + path: str | Unset = UNSET, + scope: ContentListScope | Unset = UNSET, + sort_direction: ContentListSortDirection | Unset = UNSET, + sort_field: ContentListSortField | Unset = UNSET, +) -> Response[Any | ContentListResponse]: + """List content + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + creator_id (UUID | Unset): Filter by creator user ID + folder_id (UUID | Unset): Filter by folder ID (cannot be used with path) + include (str | Unset): Comma-separated list of fields to include (e.g., _count,labels) + path (str | Unset): Filter by folder path (cannot be used with folderId) Example: + /reports/sales. + scope (ContentListScope | Unset): Filter by share scope Example: organization. + sort_direction (ContentListSortDirection | Unset): Sort direction Example: asc. + sort_field (ContentListSortField | Unset): Field to sort by Example: name. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ContentListResponse] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + creator_id=creator_id, + folder_id=folder_id, + include=include, + path=path, + scope=scope, + sort_direction=sort_direction, + sort_field=sort_field, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + creator_id: UUID | Unset = UNSET, + folder_id: UUID | Unset = UNSET, + include: str | Unset = UNSET, + path: str | Unset = UNSET, + scope: ContentListScope | Unset = UNSET, + sort_direction: ContentListSortDirection | Unset = UNSET, + sort_field: ContentListSortField | Unset = UNSET, +) -> Any | ContentListResponse | None: + """List content + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + creator_id (UUID | Unset): Filter by creator user ID + folder_id (UUID | Unset): Filter by folder ID (cannot be used with path) + include (str | Unset): Comma-separated list of fields to include (e.g., _count,labels) + path (str | Unset): Filter by folder path (cannot be used with folderId) Example: + /reports/sales. + scope (ContentListScope | Unset): Filter by share scope Example: organization. + sort_direction (ContentListSortDirection | Unset): Sort direction Example: asc. + sort_field (ContentListSortField | Unset): Field to sort by Example: name. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ContentListResponse + """ + + return ( + await asyncio_detailed( + client=client, + cursor=cursor, + page_size=page_size, + creator_id=creator_id, + folder_id=folder_id, + include=include, + path=path, + scope=scope, + sort_direction=sort_direction, + sort_field=sort_field, + ) + ).parsed diff --git a/omni_python_sdk/api/dashboards/__init__.py b/omni_python_sdk/api/dashboards/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/dashboards/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/dashboards/dashboards_download.py b/omni_python_sdk/api/dashboards/dashboards_download.py new file mode 100644 index 0000000..ed7fc96 --- /dev/null +++ b/omni_python_sdk/api/dashboards/dashboards_download.py @@ -0,0 +1,225 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.dashboards_download_body import DashboardsDownloadBody +from ...models.dashboards_download_response import DashboardsDownloadResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DashboardsDownloadBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/dashboards/{identifier}/download".format( + identifier=quote(str(identifier), safe=""), + ), + "params": params, + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DashboardsDownloadResponse | None: + if response.status_code == 200: + response_200 = DashboardsDownloadResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DashboardsDownloadResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DashboardsDownloadBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | DashboardsDownloadResponse]: + """Initiate dashboard download + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DashboardsDownloadBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DashboardsDownloadResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DashboardsDownloadBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | DashboardsDownloadResponse | None: + """Initiate dashboard download + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DashboardsDownloadBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DashboardsDownloadResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DashboardsDownloadBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | DashboardsDownloadResponse]: + """Initiate dashboard download + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DashboardsDownloadBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DashboardsDownloadResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DashboardsDownloadBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | DashboardsDownloadResponse | None: + """Initiate dashboard download + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DashboardsDownloadBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DashboardsDownloadResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/dashboards/dashboards_download_file.py b/omni_python_sdk/api/dashboards/dashboards_download_file.py new file mode 100644 index 0000000..51e77b0 --- /dev/null +++ b/omni_python_sdk/api/dashboards/dashboards_download_file.py @@ -0,0 +1,140 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + job_id: str, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/dashboards/{identifier}/download/{job_id}".format( + identifier=quote(str(identifier), safe=""), + job_id=quote(str(job_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None: + if response.status_code == 200: + return None + + if response.status_code == 202: + return None + + if response.status_code == 401: + return None + + if response.status_code == 404: + return None + + if response.status_code == 410: + return None + + if response.status_code == 500: + return None + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + job_id: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Get download file + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + job_id (str): Download job ID (UUID) Example: 123e4567-e89b-12d3-a456-426614174000. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + identifier=identifier, + job_id=job_id, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + identifier: str, + job_id: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Get download file + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + job_id (str): Download job ID (UUID) Example: 123e4567-e89b-12d3-a456-426614174000. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + identifier=identifier, + job_id=job_id, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/omni_python_sdk/api/dashboards/dashboards_download_status.py b/omni_python_sdk/api/dashboards/dashboards_download_status.py new file mode 100644 index 0000000..1bad02a --- /dev/null +++ b/omni_python_sdk/api/dashboards/dashboards_download_status.py @@ -0,0 +1,131 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + job_id: str, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/dashboards/{identifier}/download/{job_id}/status".format( + identifier=quote(str(identifier), safe=""), + job_id=quote(str(job_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None: + if response.status_code == 200: + return None + + if response.status_code == 401: + return None + + if response.status_code == 404: + return None + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + job_id: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Get download job status + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + job_id (str): Download job ID (UUID) Example: 123e4567-e89b-12d3-a456-426614174000. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + identifier=identifier, + job_id=job_id, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + identifier: str, + job_id: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Get download job status + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + job_id (str): Download job ID (UUID) Example: 123e4567-e89b-12d3-a456-426614174000. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + identifier=identifier, + job_id=job_id, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/omni_python_sdk/api/dashboards/dashboards_get_filters.py b/omni_python_sdk/api/dashboards/dashboards_get_filters.py new file mode 100644 index 0000000..56ec5de --- /dev/null +++ b/omni_python_sdk/api/dashboards/dashboards_get_filters.py @@ -0,0 +1,192 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.dashboard_filters_response import DashboardFiltersResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/dashboards/{identifier}/filters".format( + identifier=quote(str(identifier), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DashboardFiltersResponse | None: + if response.status_code == 200: + response_200 = DashboardFiltersResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DashboardFiltersResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any | DashboardFiltersResponse]: + """Get dashboard filters + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DashboardFiltersResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Any | DashboardFiltersResponse | None: + """Get dashboard filters + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DashboardFiltersResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any | DashboardFiltersResponse]: + """Get dashboard filters + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DashboardFiltersResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Any | DashboardFiltersResponse | None: + """Get dashboard filters + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DashboardFiltersResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/dashboards/dashboards_update_filters.py b/omni_python_sdk/api/dashboards/dashboards_update_filters.py new file mode 100644 index 0000000..978e9bf --- /dev/null +++ b/omni_python_sdk/api/dashboards/dashboards_update_filters.py @@ -0,0 +1,221 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.dashboard_filters_response import DashboardFiltersResponse +from ...models.dashboards_update_filters_body import DashboardsUpdateFiltersBody +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DashboardsUpdateFiltersBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/dashboards/{identifier}/filters".format( + identifier=quote(str(identifier), safe=""), + ), + "params": params, + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DashboardFiltersResponse | None: + if response.status_code == 200: + response_200 = DashboardFiltersResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DashboardFiltersResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DashboardsUpdateFiltersBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | DashboardFiltersResponse]: + """Update dashboard filters + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DashboardsUpdateFiltersBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DashboardFiltersResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DashboardsUpdateFiltersBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | DashboardFiltersResponse | None: + """Update dashboard filters + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DashboardsUpdateFiltersBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DashboardFiltersResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DashboardsUpdateFiltersBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | DashboardFiltersResponse]: + """Update dashboard filters + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DashboardsUpdateFiltersBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DashboardFiltersResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DashboardsUpdateFiltersBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | DashboardFiltersResponse | None: + """Update dashboard filters + + Args: + identifier (str): Dashboard identifier (short ID or UUID) Example: 12db1a0a. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DashboardsUpdateFiltersBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DashboardFiltersResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/__init__.py b/omni_python_sdk/api/documents/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/documents/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/documents/documents_access_list.py b/omni_python_sdk/api/documents/documents_access_list.py new file mode 100644 index 0000000..3645f9c --- /dev/null +++ b/omni_python_sdk/api/documents/documents_access_list.py @@ -0,0 +1,302 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_access_list_access_source import ( + DocumentsAccessListAccessSource, +) +from ...models.documents_access_list_response import DocumentsAccessListResponse +from ...models.documents_access_list_sort_direction import ( + DocumentsAccessListSortDirection, +) +from ...models.documents_access_list_type import DocumentsAccessListType +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: DocumentsAccessListSortDirection | Unset = "asc", + sort_field: str | Unset = UNSET, + access_source: DocumentsAccessListAccessSource | Unset = UNSET, + type_: DocumentsAccessListType | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["pageSize"] = page_size + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + params["sortField"] = sort_field + + json_access_source: str | Unset = UNSET + if not isinstance(access_source, Unset): + json_access_source = access_source + + params["accessSource"] = json_access_source + + json_type_: str | Unset = UNSET + if not isinstance(type_, Unset): + json_type_ = type_ + + params["type"] = json_type_ + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/documents/{identifier}/access-list".format( + identifier=quote(str(identifier), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsAccessListResponse | None: + if response.status_code == 200: + response_200 = DocumentsAccessListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsAccessListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: DocumentsAccessListSortDirection | Unset = "asc", + sort_field: str | Unset = UNSET, + access_source: DocumentsAccessListAccessSource | Unset = UNSET, + type_: DocumentsAccessListType | Unset = UNSET, +) -> Response[Any | DocumentsAccessListResponse]: + """List document access principals + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (DocumentsAccessListSortDirection | Unset): Sort direction (default: asc) + Default: 'asc'. Example: desc. + sort_field (str | Unset): Field to sort results by + access_source (DocumentsAccessListAccessSource | Unset): Filter by access source: direct + or folder + type_ (DocumentsAccessListType | Unset): Filter by principal type: user or userGroup + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsAccessListResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + access_source=access_source, + type_=type_, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: DocumentsAccessListSortDirection | Unset = "asc", + sort_field: str | Unset = UNSET, + access_source: DocumentsAccessListAccessSource | Unset = UNSET, + type_: DocumentsAccessListType | Unset = UNSET, +) -> Any | DocumentsAccessListResponse | None: + """List document access principals + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (DocumentsAccessListSortDirection | Unset): Sort direction (default: asc) + Default: 'asc'. Example: desc. + sort_field (str | Unset): Field to sort results by + access_source (DocumentsAccessListAccessSource | Unset): Filter by access source: direct + or folder + type_ (DocumentsAccessListType | Unset): Filter by principal type: user or userGroup + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsAccessListResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + access_source=access_source, + type_=type_, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: DocumentsAccessListSortDirection | Unset = "asc", + sort_field: str | Unset = UNSET, + access_source: DocumentsAccessListAccessSource | Unset = UNSET, + type_: DocumentsAccessListType | Unset = UNSET, +) -> Response[Any | DocumentsAccessListResponse]: + """List document access principals + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (DocumentsAccessListSortDirection | Unset): Sort direction (default: asc) + Default: 'asc'. Example: desc. + sort_field (str | Unset): Field to sort results by + access_source (DocumentsAccessListAccessSource | Unset): Filter by access source: direct + or folder + type_ (DocumentsAccessListType | Unset): Filter by principal type: user or userGroup + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsAccessListResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + access_source=access_source, + type_=type_, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: DocumentsAccessListSortDirection | Unset = "asc", + sort_field: str | Unset = UNSET, + access_source: DocumentsAccessListAccessSource | Unset = UNSET, + type_: DocumentsAccessListType | Unset = UNSET, +) -> Any | DocumentsAccessListResponse | None: + """List document access principals + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (DocumentsAccessListSortDirection | Unset): Sort direction (default: asc) + Default: 'asc'. Example: desc. + sort_field (str | Unset): Field to sort results by + access_source (DocumentsAccessListAccessSource | Unset): Filter by access source: direct + or folder + type_ (DocumentsAccessListType | Unset): Filter by principal type: user or userGroup + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsAccessListResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + access_source=access_source, + type_=type_, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_add_favorite.py b/omni_python_sdk/api/documents/documents_add_favorite.py new file mode 100644 index 0000000..d839998 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_add_favorite.py @@ -0,0 +1,128 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/documents/{identifier}/favorite".format( + identifier=quote(str(identifier), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None: + if response.status_code == 204: + return None + + if response.status_code == 401: + return None + + if response.status_code == 403: + return None + + if response.status_code == 404: + return None + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Add document to favorites + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + identifier=identifier, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Add document to favorites + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + identifier=identifier, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/omni_python_sdk/api/documents/documents_add_label.py b/omni_python_sdk/api/documents/documents_add_label.py new file mode 100644 index 0000000..44be1c9 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_add_label.py @@ -0,0 +1,134 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + label_name: str, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/documents/{identifier}/labels/{label_name}".format( + identifier=quote(str(identifier), safe=""), + label_name=quote(str(label_name), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None: + if response.status_code == 204: + return None + + if response.status_code == 401: + return None + + if response.status_code == 403: + return None + + if response.status_code == 404: + return None + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + label_name: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Add label to document + + Args: + identifier (str): Document identifier Example: abc123. + label_name (str): Label name Example: verified. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + identifier=identifier, + label_name=label_name, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + identifier: str, + label_name: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Add label to document + + Args: + identifier (str): Document identifier Example: abc123. + label_name (str): Label name Example: verified. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + identifier=identifier, + label_name=label_name, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/omni_python_sdk/api/documents/documents_add_permits.py b/omni_python_sdk/api/documents/documents_add_permits.py new file mode 100644 index 0000000..b4db66a --- /dev/null +++ b/omni_python_sdk/api/documents/documents_add_permits.py @@ -0,0 +1,195 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_add_permits_body import DocumentsAddPermitsBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsAddPermitsBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/documents/{identifier}/permissions".format( + identifier=quote(str(identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsAddPermitsBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Add document permits + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsAddPermitsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsAddPermitsBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Add document permits + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsAddPermitsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsAddPermitsBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Add document permits + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsAddPermitsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsAddPermitsBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Add document permits + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsAddPermitsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_bulk_update_labels.py b/omni_python_sdk/api/documents/documents_bulk_update_labels.py new file mode 100644 index 0000000..6104745 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_bulk_update_labels.py @@ -0,0 +1,221 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_bulk_update_labels_body import DocumentsBulkUpdateLabelsBody +from ...models.documents_bulk_update_labels_response import DocumentsBulkUpdateLabelsResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsBulkUpdateLabelsBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/documents/{identifier}/labels".format( + identifier=quote(str(identifier), safe=""), + ), + "params": params, + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsBulkUpdateLabelsResponse | None: + if response.status_code == 200: + response_200 = DocumentsBulkUpdateLabelsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsBulkUpdateLabelsResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsBulkUpdateLabelsBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | DocumentsBulkUpdateLabelsResponse]: + """Bulk update document labels + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DocumentsBulkUpdateLabelsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsBulkUpdateLabelsResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsBulkUpdateLabelsBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | DocumentsBulkUpdateLabelsResponse | None: + """Bulk update document labels + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DocumentsBulkUpdateLabelsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsBulkUpdateLabelsResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsBulkUpdateLabelsBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | DocumentsBulkUpdateLabelsResponse]: + """Bulk update document labels + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DocumentsBulkUpdateLabelsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsBulkUpdateLabelsResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsBulkUpdateLabelsBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | DocumentsBulkUpdateLabelsResponse | None: + """Bulk update document labels + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DocumentsBulkUpdateLabelsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsBulkUpdateLabelsResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_create.py b/omni_python_sdk/api/documents/documents_create.py new file mode 100644 index 0000000..f94ff72 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_create.py @@ -0,0 +1,177 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_create_body import DocumentsCreateBody +from ...models.documents_create_response import DocumentsCreateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: DocumentsCreateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/documents", + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsCreateResponse | None: + if response.status_code == 201: + response_201 = DocumentsCreateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsCreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: DocumentsCreateBody | Unset = UNSET, +) -> Response[Any | DocumentsCreateResponse]: + """Create document + + Args: + body (DocumentsCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: DocumentsCreateBody | Unset = UNSET, +) -> Any | DocumentsCreateResponse | None: + """Create document + + Args: + body (DocumentsCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsCreateResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: DocumentsCreateBody | Unset = UNSET, +) -> Response[Any | DocumentsCreateResponse]: + """Create document + + Args: + body (DocumentsCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: DocumentsCreateBody | Unset = UNSET, +) -> Any | DocumentsCreateResponse | None: + """Create document + + Args: + body (DocumentsCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsCreateResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_create_draft.py b/omni_python_sdk/api/documents/documents_create_draft.py new file mode 100644 index 0000000..8c38b5a --- /dev/null +++ b/omni_python_sdk/api/documents/documents_create_draft.py @@ -0,0 +1,197 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_create_draft_body import DocumentsCreateDraftBody +from ...models.documents_create_draft_response import DocumentsCreateDraftResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsCreateDraftBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/documents/{identifier}/draft".format( + identifier=quote(str(identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsCreateDraftResponse | None: + if response.status_code == 200: + response_200 = DocumentsCreateDraftResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsCreateDraftResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsCreateDraftBody | Unset = UNSET, +) -> Response[Any | DocumentsCreateDraftResponse]: + """Create document draft + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsCreateDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsCreateDraftResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsCreateDraftBody | Unset = UNSET, +) -> Any | DocumentsCreateDraftResponse | None: + """Create document draft + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsCreateDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsCreateDraftResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsCreateDraftBody | Unset = UNSET, +) -> Response[Any | DocumentsCreateDraftResponse]: + """Create document draft + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsCreateDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsCreateDraftResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsCreateDraftBody | Unset = UNSET, +) -> Any | DocumentsCreateDraftResponse | None: + """Create document draft + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsCreateDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsCreateDraftResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_delete.py b/omni_python_sdk/api/documents/documents_delete.py new file mode 100644 index 0000000..81132ea --- /dev/null +++ b/omni_python_sdk/api/documents/documents_delete.py @@ -0,0 +1,169 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.success_response import SuccessResponse +from ...types import Response + + +def _get_kwargs( + identifier: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/documents/{identifier}".format( + identifier=quote(str(identifier), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Delete document + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Delete document + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Delete document + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Delete document + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_discard_draft.py b/omni_python_sdk/api/documents/documents_discard_draft.py new file mode 100644 index 0000000..381a2c0 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_discard_draft.py @@ -0,0 +1,193 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_discard_draft_body import DocumentsDiscardDraftBody +from ...models.documents_discard_draft_response import DocumentsDiscardDraftResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsDiscardDraftBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/documents/{identifier}/draft".format( + identifier=quote(str(identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsDiscardDraftResponse | None: + if response.status_code == 200: + response_200 = DocumentsDiscardDraftResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsDiscardDraftResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsDiscardDraftBody | Unset = UNSET, +) -> Response[Any | DocumentsDiscardDraftResponse]: + """Discard document draft + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsDiscardDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsDiscardDraftResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsDiscardDraftBody | Unset = UNSET, +) -> Any | DocumentsDiscardDraftResponse | None: + """Discard document draft + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsDiscardDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsDiscardDraftResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsDiscardDraftBody | Unset = UNSET, +) -> Response[Any | DocumentsDiscardDraftResponse]: + """Discard document draft + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsDiscardDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsDiscardDraftResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsDiscardDraftBody | Unset = UNSET, +) -> Any | DocumentsDiscardDraftResponse | None: + """Discard document draft + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsDiscardDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsDiscardDraftResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_duplicate.py b/omni_python_sdk/api/documents/documents_duplicate.py new file mode 100644 index 0000000..1926dda --- /dev/null +++ b/omni_python_sdk/api/documents/documents_duplicate.py @@ -0,0 +1,221 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_duplicate_body import DocumentsDuplicateBody +from ...models.documents_duplicate_response import DocumentsDuplicateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsDuplicateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/documents/{identifier}/duplicate".format( + identifier=quote(str(identifier), safe=""), + ), + "params": params, + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsDuplicateResponse | None: + if response.status_code == 201: + response_201 = DocumentsDuplicateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsDuplicateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsDuplicateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | DocumentsDuplicateResponse]: + """Duplicate document + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DocumentsDuplicateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsDuplicateResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsDuplicateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | DocumentsDuplicateResponse | None: + """Duplicate document + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DocumentsDuplicateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsDuplicateResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsDuplicateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | DocumentsDuplicateResponse]: + """Duplicate document + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DocumentsDuplicateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsDuplicateResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsDuplicateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | DocumentsDuplicateResponse | None: + """Duplicate document + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (DocumentsDuplicateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsDuplicateResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_get.py b/omni_python_sdk/api/documents/documents_get.py new file mode 100644 index 0000000..ef92dc9 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_get.py @@ -0,0 +1,191 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_get_response import DocumentsGetResponse +from ...types import Response + + +def _get_kwargs( + identifier: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/documents/{identifier}".format( + identifier=quote(str(identifier), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsGetResponse | None: + if response.status_code == 200: + response_200 = DocumentsGetResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsGetResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | DocumentsGetResponse]: + """Get document + + Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a + document, modify the response, and PUT it back to update. Only dashboard documents are supported; + analysis documents return 400. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsGetResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Any | DocumentsGetResponse | None: + """Get document + + Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a + document, modify the response, and PUT it back to update. Only dashboard documents are supported; + analysis documents return 400. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsGetResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | DocumentsGetResponse]: + """Get document + + Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a + document, modify the response, and PUT it back to update. Only dashboard documents are supported; + analysis documents return 400. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsGetResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Any | DocumentsGetResponse | None: + """Get document + + Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a + document, modify the response, and PUT it back to update. Only dashboard documents are supported; + analysis documents return 400. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsGetResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_get_permissions.py b/omni_python_sdk/api/documents/documents_get_permissions.py new file mode 100644 index 0000000..e40f3d7 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_get_permissions.py @@ -0,0 +1,194 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_get_permissions_response import DocumentsGetPermissionsResponse +from ...types import UNSET, Response + + +def _get_kwargs( + identifier: str, + *, + user_id: UUID, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/documents/{identifier}/permissions".format( + identifier=quote(str(identifier), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsGetPermissionsResponse | None: + if response.status_code == 200: + response_200 = DocumentsGetPermissionsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsGetPermissionsResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID, +) -> Response[Any | DocumentsGetPermissionsResponse]: + """Get document permissions + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID): User membership ID to check permissions for + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsGetPermissionsResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID, +) -> Any | DocumentsGetPermissionsResponse | None: + """Get document permissions + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID): User membership ID to check permissions for + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsGetPermissionsResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID, +) -> Response[Any | DocumentsGetPermissionsResponse]: + """Get document permissions + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID): User membership ID to check permissions for + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsGetPermissionsResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID, +) -> Any | DocumentsGetPermissionsResponse | None: + """Get document permissions + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID): User membership ID to check permissions for + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsGetPermissionsResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_get_queries.py b/omni_python_sdk/api/documents/documents_get_queries.py new file mode 100644 index 0000000..5be27af --- /dev/null +++ b/omni_python_sdk/api/documents/documents_get_queries.py @@ -0,0 +1,171 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_get_queries_response import DocumentsGetQueriesResponse +from ...types import Response + + +def _get_kwargs( + identifier: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/documents/{identifier}/queries".format( + identifier=quote(str(identifier), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsGetQueriesResponse | None: + if response.status_code == 200: + response_200 = DocumentsGetQueriesResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsGetQueriesResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | DocumentsGetQueriesResponse]: + """List document queries + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsGetQueriesResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Any | DocumentsGetQueriesResponse | None: + """List document queries + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsGetQueriesResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | DocumentsGetQueriesResponse]: + """List document queries + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsGetQueriesResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Any | DocumentsGetQueriesResponse | None: + """List document queries + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsGetQueriesResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_list.py b/omni_python_sdk/api/documents/documents_list.py new file mode 100644 index 0000000..9a9a07c --- /dev/null +++ b/omni_python_sdk/api/documents/documents_list.py @@ -0,0 +1,320 @@ +from http import HTTPStatus +from typing import Any, cast +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_list_response import DocumentsListResponse +from ...models.documents_list_sort_direction import DocumentsListSortDirection +from ...models.documents_list_sort_field import DocumentsListSortField +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + creator_id: UUID | Unset = UNSET, + cursor: str | Unset = UNSET, + folder_id: UUID | Unset = UNSET, + include: str | Unset = UNSET, + labels: str | Unset = UNSET, + page_size: int | Unset = 50, + sort_direction: DocumentsListSortDirection | Unset = "asc", + sort_field: DocumentsListSortField | Unset = "name", + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_creator_id: str | Unset = UNSET + if not isinstance(creator_id, Unset): + json_creator_id = str(creator_id) + params["creatorId"] = json_creator_id + + params["cursor"] = cursor + + json_folder_id: str | Unset = UNSET + if not isinstance(folder_id, Unset): + json_folder_id = str(folder_id) + params["folderId"] = json_folder_id + + params["include"] = include + + params["labels"] = labels + + params["pageSize"] = page_size + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + json_sort_field: str | Unset = UNSET + if not isinstance(sort_field, Unset): + json_sort_field = sort_field + + params["sortField"] = json_sort_field + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/documents", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsListResponse | None: + if response.status_code == 200: + response_200 = DocumentsListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + creator_id: UUID | Unset = UNSET, + cursor: str | Unset = UNSET, + folder_id: UUID | Unset = UNSET, + include: str | Unset = UNSET, + labels: str | Unset = UNSET, + page_size: int | Unset = 50, + sort_direction: DocumentsListSortDirection | Unset = "asc", + sort_field: DocumentsListSortField | Unset = "name", + user_id: UUID | Unset = UNSET, +) -> Response[Any | DocumentsListResponse]: + """List documents + + Args: + creator_id (UUID | Unset): Filter by creator membership ID + cursor (str | Unset): Cursor for pagination + folder_id (UUID | Unset): Filter by folder ID + include (str | Unset): Comma-separated list of additional fields to include: _count, + labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId + or user-scoped key and cannot be combined with onlyFavorites or folderId. Example: + _count,labels. + labels (str | Unset): Comma-separated list of label names to filter by Example: + verified,important. + page_size (int | Unset): Number of records per page Default: 50. + sort_direction (DocumentsListSortDirection | Unset): Sort direction Default: 'asc'. + sort_field (DocumentsListSortField | Unset): Field to sort by Default: 'name'. + user_id (UUID | Unset): Filter documents visible to this membership ID + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsListResponse] + """ + + kwargs = _get_kwargs( + creator_id=creator_id, + cursor=cursor, + folder_id=folder_id, + include=include, + labels=labels, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + creator_id: UUID | Unset = UNSET, + cursor: str | Unset = UNSET, + folder_id: UUID | Unset = UNSET, + include: str | Unset = UNSET, + labels: str | Unset = UNSET, + page_size: int | Unset = 50, + sort_direction: DocumentsListSortDirection | Unset = "asc", + sort_field: DocumentsListSortField | Unset = "name", + user_id: UUID | Unset = UNSET, +) -> Any | DocumentsListResponse | None: + """List documents + + Args: + creator_id (UUID | Unset): Filter by creator membership ID + cursor (str | Unset): Cursor for pagination + folder_id (UUID | Unset): Filter by folder ID + include (str | Unset): Comma-separated list of additional fields to include: _count, + labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId + or user-scoped key and cannot be combined with onlyFavorites or folderId. Example: + _count,labels. + labels (str | Unset): Comma-separated list of label names to filter by Example: + verified,important. + page_size (int | Unset): Number of records per page Default: 50. + sort_direction (DocumentsListSortDirection | Unset): Sort direction Default: 'asc'. + sort_field (DocumentsListSortField | Unset): Field to sort by Default: 'name'. + user_id (UUID | Unset): Filter documents visible to this membership ID + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsListResponse + """ + + return sync_detailed( + client=client, + creator_id=creator_id, + cursor=cursor, + folder_id=folder_id, + include=include, + labels=labels, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + creator_id: UUID | Unset = UNSET, + cursor: str | Unset = UNSET, + folder_id: UUID | Unset = UNSET, + include: str | Unset = UNSET, + labels: str | Unset = UNSET, + page_size: int | Unset = 50, + sort_direction: DocumentsListSortDirection | Unset = "asc", + sort_field: DocumentsListSortField | Unset = "name", + user_id: UUID | Unset = UNSET, +) -> Response[Any | DocumentsListResponse]: + """List documents + + Args: + creator_id (UUID | Unset): Filter by creator membership ID + cursor (str | Unset): Cursor for pagination + folder_id (UUID | Unset): Filter by folder ID + include (str | Unset): Comma-separated list of additional fields to include: _count, + labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId + or user-scoped key and cannot be combined with onlyFavorites or folderId. Example: + _count,labels. + labels (str | Unset): Comma-separated list of label names to filter by Example: + verified,important. + page_size (int | Unset): Number of records per page Default: 50. + sort_direction (DocumentsListSortDirection | Unset): Sort direction Default: 'asc'. + sort_field (DocumentsListSortField | Unset): Field to sort by Default: 'name'. + user_id (UUID | Unset): Filter documents visible to this membership ID + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsListResponse] + """ + + kwargs = _get_kwargs( + creator_id=creator_id, + cursor=cursor, + folder_id=folder_id, + include=include, + labels=labels, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + creator_id: UUID | Unset = UNSET, + cursor: str | Unset = UNSET, + folder_id: UUID | Unset = UNSET, + include: str | Unset = UNSET, + labels: str | Unset = UNSET, + page_size: int | Unset = 50, + sort_direction: DocumentsListSortDirection | Unset = "asc", + sort_field: DocumentsListSortField | Unset = "name", + user_id: UUID | Unset = UNSET, +) -> Any | DocumentsListResponse | None: + """List documents + + Args: + creator_id (UUID | Unset): Filter by creator membership ID + cursor (str | Unset): Cursor for pagination + folder_id (UUID | Unset): Filter by folder ID + include (str | Unset): Comma-separated list of additional fields to include: _count, + labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId + or user-scoped key and cannot be combined with onlyFavorites or folderId. Example: + _count,labels. + labels (str | Unset): Comma-separated list of label names to filter by Example: + verified,important. + page_size (int | Unset): Number of records per page Default: 50. + sort_direction (DocumentsListSortDirection | Unset): Sort direction Default: 'asc'. + sort_field (DocumentsListSortField | Unset): Field to sort by Default: 'name'. + user_id (UUID | Unset): Filter documents visible to this membership ID + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsListResponse + """ + + return ( + await asyncio_detailed( + client=client, + creator_id=creator_id, + cursor=cursor, + folder_id=folder_id, + include=include, + labels=labels, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_list_drafts.py b/omni_python_sdk/api/documents/documents_list_drafts.py new file mode 100644 index 0000000..54e5b9f --- /dev/null +++ b/omni_python_sdk/api/documents/documents_list_drafts.py @@ -0,0 +1,225 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.api_draft import ApiDraft +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + include: str | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["include"] = include + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/documents/{identifier}/drafts".format( + identifier=quote(str(identifier), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | list[ApiDraft] | None: + if response.status_code == 200: + response_200 = [] + _response_200 = response.json() + for componentsschemas_documents_list_drafts_response_item_data in _response_200: + componentsschemas_documents_list_drafts_response_item = ApiDraft.from_dict( + componentsschemas_documents_list_drafts_response_item_data + ) + + response_200.append(componentsschemas_documents_list_drafts_response_item) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | list[ApiDraft]]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + include: str | Unset = UNSET, +) -> Response[Any | list[ApiDraft]]: + """List document drafts + + Lists drafts for a document with branch context. By default only active drafts are returned; pass + `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by + `createdAt` descending. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + include (str | Unset): Comma-separated list of additional drafts to include. Only + "archived" is recognized — when present, soft-deleted drafts (retained ~7 days) are + returned alongside active drafts. Example: archived. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | list[ApiDraft]] + """ + + kwargs = _get_kwargs( + identifier=identifier, + include=include, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + include: str | Unset = UNSET, +) -> Any | list[ApiDraft] | None: + """List document drafts + + Lists drafts for a document with branch context. By default only active drafts are returned; pass + `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by + `createdAt` descending. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + include (str | Unset): Comma-separated list of additional drafts to include. Only + "archived" is recognized — when present, soft-deleted drafts (retained ~7 days) are + returned alongside active drafts. Example: archived. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | list[ApiDraft] + """ + + return sync_detailed( + identifier=identifier, + client=client, + include=include, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + include: str | Unset = UNSET, +) -> Response[Any | list[ApiDraft]]: + """List document drafts + + Lists drafts for a document with branch context. By default only active drafts are returned; pass + `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by + `createdAt` descending. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + include (str | Unset): Comma-separated list of additional drafts to include. Only + "archived" is recognized — when present, soft-deleted drafts (retained ~7 days) are + returned alongside active drafts. Example: archived. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | list[ApiDraft]] + """ + + kwargs = _get_kwargs( + identifier=identifier, + include=include, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + include: str | Unset = UNSET, +) -> Any | list[ApiDraft] | None: + """List document drafts + + Lists drafts for a document with branch context. By default only active drafts are returned; pass + `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by + `createdAt` descending. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + include (str | Unset): Comma-separated list of additional drafts to include. Only + "archived" is recognized — when present, soft-deleted drafts (retained ~7 days) are + returned alongside active drafts. Example: archived. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | list[ApiDraft] + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + include=include, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_list_favorites.py b/omni_python_sdk/api/documents/documents_list_favorites.py new file mode 100644 index 0000000..b540340 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_list_favorites.py @@ -0,0 +1,261 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_list_favorites_response import DocumentsListFavoritesResponse +from ...models.documents_list_favorites_sort_direction import ( + DocumentsListFavoritesSortDirection, +) +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: DocumentsListFavoritesSortDirection | Unset = "asc", +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["pageSize"] = page_size + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/documents/{identifier}/favorites".format( + identifier=quote(str(identifier), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsListFavoritesResponse | None: + if response.status_code == 200: + response_200 = DocumentsListFavoritesResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsListFavoritesResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: DocumentsListFavoritesSortDirection | Unset = "asc", +) -> Response[Any | DocumentsListFavoritesResponse]: + """List users who favorited the document + + Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric + counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need + to preserve favorites when replacing documents, without iterating every user in the organization. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (DocumentsListFavoritesSortDirection | Unset): Sort direction by + favoritedAt (default: asc — oldest first) Default: 'asc'. Example: desc. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsListFavoritesResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: DocumentsListFavoritesSortDirection | Unset = "asc", +) -> Any | DocumentsListFavoritesResponse | None: + """List users who favorited the document + + Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric + counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need + to preserve favorites when replacing documents, without iterating every user in the organization. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (DocumentsListFavoritesSortDirection | Unset): Sort direction by + favoritedAt (default: asc — oldest first) Default: 'asc'. Example: desc. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsListFavoritesResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: DocumentsListFavoritesSortDirection | Unset = "asc", +) -> Response[Any | DocumentsListFavoritesResponse]: + """List users who favorited the document + + Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric + counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need + to preserve favorites when replacing documents, without iterating every user in the organization. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (DocumentsListFavoritesSortDirection | Unset): Sort direction by + favoritedAt (default: asc — oldest first) Default: 'asc'. Example: desc. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsListFavoritesResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: DocumentsListFavoritesSortDirection | Unset = "asc", +) -> Any | DocumentsListFavoritesResponse | None: + """List users who favorited the document + + Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric + counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need + to preserve favorites when replacing documents, without iterating every user in the organization. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (DocumentsListFavoritesSortDirection | Unset): Sort direction by + favoritedAt (default: asc — oldest first) Default: 'asc'. Example: desc. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsListFavoritesResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_move.py b/omni_python_sdk/api/documents/documents_move.py new file mode 100644 index 0000000..d52560b --- /dev/null +++ b/omni_python_sdk/api/documents/documents_move.py @@ -0,0 +1,195 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_move_body import DocumentsMoveBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsMoveBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/documents/{identifier}/move".format( + identifier=quote(str(identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsMoveBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Move document + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsMoveBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsMoveBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Move document + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsMoveBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsMoveBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Move document + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsMoveBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsMoveBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Move document + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsMoveBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_put.py b/omni_python_sdk/api/documents/documents_put.py new file mode 100644 index 0000000..03d5dff --- /dev/null +++ b/omni_python_sdk/api/documents/documents_put.py @@ -0,0 +1,237 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_put_body import DocumentsPutBody +from ...models.documents_put_response import DocumentsPutResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsPutBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/documents/{identifier}".format( + identifier=quote(str(identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsPutResponse | None: + if response.status_code == 200: + response_200 = DocumentsPutResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsPutResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsPutBody | Unset = UNSET, +) -> Response[Any | DocumentsPutResponse]: + """Replace document (full replacement) + + **Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). + Scheduled for removal on July 31, 2026 (see the `Sunset` response header). + + Updates a document with the specified identifier. This endpoint performs a full resource replacement + — all required fields must be provided and existing query presentations are replaced entirely. Only + dashboard documents are supported; analysis documents and documents without an associated dashboard + return 400. For published documents, the update goes through a draft/publish workflow automatically; + if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsPutBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsPutResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsPutBody | Unset = UNSET, +) -> Any | DocumentsPutResponse | None: + """Replace document (full replacement) + + **Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). + Scheduled for removal on July 31, 2026 (see the `Sunset` response header). + + Updates a document with the specified identifier. This endpoint performs a full resource replacement + — all required fields must be provided and existing query presentations are replaced entirely. Only + dashboard documents are supported; analysis documents and documents without an associated dashboard + return 400. For published documents, the update goes through a draft/publish workflow automatically; + if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsPutBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsPutResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsPutBody | Unset = UNSET, +) -> Response[Any | DocumentsPutResponse]: + """Replace document (full replacement) + + **Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). + Scheduled for removal on July 31, 2026 (see the `Sunset` response header). + + Updates a document with the specified identifier. This endpoint performs a full resource replacement + — all required fields must be provided and existing query presentations are replaced entirely. Only + dashboard documents are supported; analysis documents and documents without an associated dashboard + return 400. For published documents, the update goes through a draft/publish workflow automatically; + if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsPutBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsPutResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsPutBody | Unset = UNSET, +) -> Any | DocumentsPutResponse | None: + """Replace document (full replacement) + + **Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). + Scheduled for removal on July 31, 2026 (see the `Sunset` response header). + + Updates a document with the specified identifier. This endpoint performs a full resource replacement + — all required fields must be provided and existing query presentations are replaced entirely. Only + dashboard documents are supported; analysis documents and documents without an associated dashboard + return 400. For published documents, the update goes through a draft/publish workflow automatically; + if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsPutBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsPutResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_remove_favorite.py b/omni_python_sdk/api/documents/documents_remove_favorite.py new file mode 100644 index 0000000..55821d5 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_remove_favorite.py @@ -0,0 +1,128 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/documents/{identifier}/favorite".format( + identifier=quote(str(identifier), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None: + if response.status_code == 204: + return None + + if response.status_code == 401: + return None + + if response.status_code == 403: + return None + + if response.status_code == 404: + return None + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Remove document from favorites + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + identifier=identifier, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Remove document from favorites + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + identifier=identifier, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/omni_python_sdk/api/documents/documents_remove_label.py b/omni_python_sdk/api/documents/documents_remove_label.py new file mode 100644 index 0000000..03e647e --- /dev/null +++ b/omni_python_sdk/api/documents/documents_remove_label.py @@ -0,0 +1,134 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + label_name: str, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/documents/{identifier}/labels/{label_name}".format( + identifier=quote(str(identifier), safe=""), + label_name=quote(str(label_name), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None: + if response.status_code == 204: + return None + + if response.status_code == 401: + return None + + if response.status_code == 403: + return None + + if response.status_code == 404: + return None + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + label_name: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Remove label from document + + Args: + identifier (str): Document identifier Example: abc123. + label_name (str): Label name Example: verified. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + identifier=identifier, + label_name=label_name, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + identifier: str, + label_name: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Remove label from document + + Args: + identifier (str): Document identifier Example: abc123. + label_name (str): Label name Example: verified. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + identifier=identifier, + label_name=label_name, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/omni_python_sdk/api/documents/documents_revoke_permits.py b/omni_python_sdk/api/documents/documents_revoke_permits.py new file mode 100644 index 0000000..8245834 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_revoke_permits.py @@ -0,0 +1,195 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_revoke_permits_body import DocumentsRevokePermitsBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsRevokePermitsBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/documents/{identifier}/permissions".format( + identifier=quote(str(identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsRevokePermitsBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Revoke document permits + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsRevokePermitsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsRevokePermitsBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Revoke document permits + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsRevokePermitsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsRevokePermitsBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Revoke document permits + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsRevokePermitsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsRevokePermitsBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Revoke document permits + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsRevokePermitsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_transfer_ownership.py b/omni_python_sdk/api/documents/documents_transfer_ownership.py new file mode 100644 index 0000000..2339e0e --- /dev/null +++ b/omni_python_sdk/api/documents/documents_transfer_ownership.py @@ -0,0 +1,195 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_transfer_ownership_body import DocumentsTransferOwnershipBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsTransferOwnershipBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/documents/{identifier}/transfer-ownership".format( + identifier=quote(str(identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsTransferOwnershipBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Transfer document ownership + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsTransferOwnershipBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsTransferOwnershipBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Transfer document ownership + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsTransferOwnershipBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsTransferOwnershipBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Transfer document ownership + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsTransferOwnershipBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsTransferOwnershipBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Transfer document ownership + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsTransferOwnershipBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_update.py b/omni_python_sdk/api/documents/documents_update.py new file mode 100644 index 0000000..cac7982 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_update.py @@ -0,0 +1,237 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_update_body import DocumentsUpdateBody +from ...models.documents_update_response import DocumentsUpdateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsUpdateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/documents/{identifier}".format( + identifier=quote(str(identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsUpdateResponse | None: + if response.status_code == 200: + response_200 = DocumentsUpdateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsUpdateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpdateBody | Unset = UNSET, +) -> Response[Any | DocumentsUpdateResponse]: + """Rename document + + **Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). + Scheduled for removal on July 31, 2026 (see the `Sunset` response header). + + Updates a document's name, description, and/or identifier. This is a partial update — only provided + fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. + When `identifier` is changed, the previous identifier is retained in the document identifier history + and continues to redirect. For published documents, the update goes through a draft/publish workflow + automatically. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsUpdateResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpdateBody | Unset = UNSET, +) -> Any | DocumentsUpdateResponse | None: + """Rename document + + **Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). + Scheduled for removal on July 31, 2026 (see the `Sunset` response header). + + Updates a document's name, description, and/or identifier. This is a partial update — only provided + fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. + When `identifier` is changed, the previous identifier is retained in the document identifier history + and continues to redirect. For published documents, the update goes through a draft/publish workflow + automatically. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsUpdateResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpdateBody | Unset = UNSET, +) -> Response[Any | DocumentsUpdateResponse]: + """Rename document + + **Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). + Scheduled for removal on July 31, 2026 (see the `Sunset` response header). + + Updates a document's name, description, and/or identifier. This is a partial update — only provided + fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. + When `identifier` is changed, the previous identifier is retained in the document identifier history + and continues to redirect. For published documents, the update goes through a draft/publish workflow + automatically. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsUpdateResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpdateBody | Unset = UNSET, +) -> Any | DocumentsUpdateResponse | None: + """Rename document + + **Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). + Scheduled for removal on July 31, 2026 (see the `Sunset` response header). + + Updates a document's name, description, and/or identifier. This is a partial update — only provided + fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. + When `identifier` is changed, the previous identifier is retained in the document identifier history + and continues to redirect. For published documents, the update goes through a draft/publish workflow + automatically. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsUpdateResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_update_permission_settings.py b/omni_python_sdk/api/documents/documents_update_permission_settings.py new file mode 100644 index 0000000..1540bf6 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_update_permission_settings.py @@ -0,0 +1,195 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_update_permission_settings_body import DocumentsUpdatePermissionSettingsBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsUpdatePermissionSettingsBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/documents/{identifier}/permissions".format( + identifier=quote(str(identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpdatePermissionSettingsBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Update document permission settings + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpdatePermissionSettingsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpdatePermissionSettingsBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Update document permission settings + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpdatePermissionSettingsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpdatePermissionSettingsBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Update document permission settings + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpdatePermissionSettingsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpdatePermissionSettingsBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Update document permission settings + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpdatePermissionSettingsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_update_permits.py b/omni_python_sdk/api/documents/documents_update_permits.py new file mode 100644 index 0000000..62ccbf8 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_update_permits.py @@ -0,0 +1,195 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_update_permits_body import DocumentsUpdatePermitsBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsUpdatePermitsBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/documents/{identifier}/permissions".format( + identifier=quote(str(identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpdatePermitsBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Update document permits + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpdatePermitsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpdatePermitsBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Update document permits + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpdatePermitsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpdatePermitsBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Update document permits + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpdatePermitsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpdatePermitsBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Update document permits + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpdatePermitsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_upgrade_layout.py b/omni_python_sdk/api/documents/documents_upgrade_layout.py new file mode 100644 index 0000000..494ab93 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_upgrade_layout.py @@ -0,0 +1,221 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_upgrade_layout_body import DocumentsUpgradeLayoutBody +from ...models.documents_upgrade_layout_response import DocumentsUpgradeLayoutResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsUpgradeLayoutBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/documents/{identifier}/upgrade".format( + identifier=quote(str(identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsUpgradeLayoutResponse | None: + if response.status_code == 200: + response_200 = DocumentsUpgradeLayoutResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsUpgradeLayoutResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpgradeLayoutBody | Unset = UNSET, +) -> Response[Any | DocumentsUpgradeLayoutResponse]: + r"""Upgrade dashboard layout + + Upgrades a document to the advanced dashboard layout (the \"File > Upgrade layout\" UI action). No- + ops when the document already has advanced layout. For published documents the upgrade goes through + a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless + `clearExistingDraft` is set to `true`. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpgradeLayoutBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsUpgradeLayoutResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpgradeLayoutBody | Unset = UNSET, +) -> Any | DocumentsUpgradeLayoutResponse | None: + r"""Upgrade dashboard layout + + Upgrades a document to the advanced dashboard layout (the \"File > Upgrade layout\" UI action). No- + ops when the document already has advanced layout. For published documents the upgrade goes through + a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless + `clearExistingDraft` is set to `true`. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpgradeLayoutBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsUpgradeLayoutResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpgradeLayoutBody | Unset = UNSET, +) -> Response[Any | DocumentsUpgradeLayoutResponse]: + r"""Upgrade dashboard layout + + Upgrades a document to the advanced dashboard layout (the \"File > Upgrade layout\" UI action). No- + ops when the document already has advanced layout. For published documents the upgrade goes through + a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless + `clearExistingDraft` is set to `true`. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpgradeLayoutBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsUpgradeLayoutResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsUpgradeLayoutBody | Unset = UNSET, +) -> Any | DocumentsUpgradeLayoutResponse | None: + r"""Upgrade dashboard layout + + Upgrades a document to the advanced dashboard layout (the \"File > Upgrade layout\" UI action). No- + ops when the document already has advanced layout. For published documents the upgrade goes through + a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless + `clearExistingDraft` is set to `true`. + + Args: + identifier (str): Document identifier (either document ID or identifier slug) Example: + abc123. + body (DocumentsUpgradeLayoutBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsUpgradeLayoutResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_v2_create.py b/omni_python_sdk/api/documents/documents_v2_create.py new file mode 100644 index 0000000..79a1a26 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_v2_create.py @@ -0,0 +1,240 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_v2_create_body import DocumentsV2CreateBody +from ...models.documents_v2_create_response import DocumentsV2CreateResponse +from ...types import Response + + +def _get_kwargs( + *, + body: DocumentsV2CreateBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v2/documents", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsV2CreateResponse | None: + if response.status_code == 201: + response_201 = DocumentsV2CreateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsV2CreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: DocumentsV2CreateBody, +) -> Response[Any | DocumentsV2CreateResponse]: + r"""Create document + + Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, + optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body — + `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile + identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the + single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed. + + When `containers` is omitted, every dashboard-eligible tile is auto-placed in a default layout. When + `containers` is present, it fully defines the layout — tiles it does not reference are stored but + not rendered. Send `containers: null` to create a workbook-only document with no dashboard + (`controls` and `settings` must then be omitted); an empty `containers: []` is rejected. + + The new document is published live before the response returns. As a first publish of brand-new + content it is not subject to the org’s `requirePullRequestToPublish` policy (which gates edits to + existing content). + + Args: + body (DocumentsV2CreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2CreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: DocumentsV2CreateBody, +) -> Any | DocumentsV2CreateResponse | None: + r"""Create document + + Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, + optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body — + `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile + identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the + single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed. + + When `containers` is omitted, every dashboard-eligible tile is auto-placed in a default layout. When + `containers` is present, it fully defines the layout — tiles it does not reference are stored but + not rendered. Send `containers: null` to create a workbook-only document with no dashboard + (`controls` and `settings` must then be omitted); an empty `containers: []` is rejected. + + The new document is published live before the response returns. As a first publish of brand-new + content it is not subject to the org’s `requirePullRequestToPublish` policy (which gates edits to + existing content). + + Args: + body (DocumentsV2CreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2CreateResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: DocumentsV2CreateBody, +) -> Response[Any | DocumentsV2CreateResponse]: + r"""Create document + + Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, + optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body — + `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile + identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the + single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed. + + When `containers` is omitted, every dashboard-eligible tile is auto-placed in a default layout. When + `containers` is present, it fully defines the layout — tiles it does not reference are stored but + not rendered. Send `containers: null` to create a workbook-only document with no dashboard + (`controls` and `settings` must then be omitted); an empty `containers: []` is rejected. + + The new document is published live before the response returns. As a first publish of brand-new + content it is not subject to the org’s `requirePullRequestToPublish` policy (which gates edits to + existing content). + + Args: + body (DocumentsV2CreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2CreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: DocumentsV2CreateBody, +) -> Any | DocumentsV2CreateResponse | None: + r"""Create document + + Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, + optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body — + `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile + identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the + single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed. + + When `containers` is omitted, every dashboard-eligible tile is auto-placed in a default layout. When + `containers` is present, it fully defines the layout — tiles it does not reference are stored but + not rendered. Send `containers: null` to create a workbook-only document with no dashboard + (`controls` and `settings` must then be omitted); an empty `containers: []` is rejected. + + The new document is published live before the response returns. As a first publish of brand-new + content it is not subject to the org’s `requirePullRequestToPublish` policy (which gates edits to + existing content). + + Args: + body (DocumentsV2CreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2CreateResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_v2_get.py b/omni_python_sdk/api/documents/documents_v2_get.py new file mode 100644 index 0000000..f6a3477 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_v2_get.py @@ -0,0 +1,253 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_v2_get_pretty import DocumentsV2GetPretty +from ...models.documents_v2_read_response import DocumentsV2ReadResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + pretty: DocumentsV2GetPretty | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_pretty: str | Unset = UNSET + if not isinstance(pretty, Unset): + json_pretty = pretty + + params["pretty"] = json_pretty + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v2/documents/{identifier}".format( + identifier=quote(str(identifier), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsV2ReadResponse | None: + if response.status_code == 200: + response_200 = DocumentsV2ReadResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 422: + response_422 = cast(Any, None) + return response_422 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsV2ReadResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + pretty: DocumentsV2GetPretty | Unset = UNSET, +) -> Response[Any | DocumentsV2ReadResponse]: + r"""Read document state + + Read the document's published state — draft edits are never surfaced here. When a draft exists, read + it via `GET /api/v2/documents/{identifier}/draft/{draftIdentifier}` before round-tripping the + response into a draft PATCH, so you patch the draft's own content rather than published content over + it. Returns the full `DocumentsV2ReadResponse` shape. + + The response is structured so a caller can take it verbatim and submit it as the body of the draft + PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, + `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need + to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` + values also round-trip unchanged. + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + pretty (DocumentsV2GetPretty | Unset): Set `true` or `1` to pretty-print (2-space indent) + the response; `false` / `0` (the default) is compact. Key ordering is deterministic + regardless. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2ReadResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + pretty=pretty, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + pretty: DocumentsV2GetPretty | Unset = UNSET, +) -> Any | DocumentsV2ReadResponse | None: + r"""Read document state + + Read the document's published state — draft edits are never surfaced here. When a draft exists, read + it via `GET /api/v2/documents/{identifier}/draft/{draftIdentifier}` before round-tripping the + response into a draft PATCH, so you patch the draft's own content rather than published content over + it. Returns the full `DocumentsV2ReadResponse` shape. + + The response is structured so a caller can take it verbatim and submit it as the body of the draft + PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, + `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need + to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` + values also round-trip unchanged. + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + pretty (DocumentsV2GetPretty | Unset): Set `true` or `1` to pretty-print (2-space indent) + the response; `false` / `0` (the default) is compact. Key ordering is deterministic + regardless. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2ReadResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + pretty=pretty, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + pretty: DocumentsV2GetPretty | Unset = UNSET, +) -> Response[Any | DocumentsV2ReadResponse]: + r"""Read document state + + Read the document's published state — draft edits are never surfaced here. When a draft exists, read + it via `GET /api/v2/documents/{identifier}/draft/{draftIdentifier}` before round-tripping the + response into a draft PATCH, so you patch the draft's own content rather than published content over + it. Returns the full `DocumentsV2ReadResponse` shape. + + The response is structured so a caller can take it verbatim and submit it as the body of the draft + PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, + `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need + to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` + values also round-trip unchanged. + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + pretty (DocumentsV2GetPretty | Unset): Set `true` or `1` to pretty-print (2-space indent) + the response; `false` / `0` (the default) is compact. Key ordering is deterministic + regardless. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2ReadResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + pretty=pretty, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + pretty: DocumentsV2GetPretty | Unset = UNSET, +) -> Any | DocumentsV2ReadResponse | None: + r"""Read document state + + Read the document's published state — draft edits are never surfaced here. When a draft exists, read + it via `GET /api/v2/documents/{identifier}/draft/{draftIdentifier}` before round-tripping the + response into a draft PATCH, so you patch the draft's own content rather than published content over + it. Returns the full `DocumentsV2ReadResponse` shape. + + The response is structured so a caller can take it verbatim and submit it as the body of the draft + PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, + `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need + to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` + values also round-trip unchanged. + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + pretty (DocumentsV2GetPretty | Unset): Set `true` or `1` to pretty-print (2-space indent) + the response; `false` / `0` (the default) is compact. Key ordering is deterministic + regardless. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2ReadResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + pretty=pretty, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_v2_get_draft.py b/omni_python_sdk/api/documents/documents_v2_get_draft.py new file mode 100644 index 0000000..2d9d2f5 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_v2_get_draft.py @@ -0,0 +1,259 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_v2_get_draft_pretty import DocumentsV2GetDraftPretty +from ...models.documents_v2_read_response import DocumentsV2ReadResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + draft_identifier: str, + *, + pretty: DocumentsV2GetDraftPretty | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_pretty: str | Unset = UNSET + if not isinstance(pretty, Unset): + json_pretty = pretty + + params["pretty"] = json_pretty + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v2/documents/{identifier}/draft/{draft_identifier}".format( + identifier=quote(str(identifier), safe=""), + draft_identifier=quote(str(draft_identifier), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsV2ReadResponse | None: + if response.status_code == 200: + response_200 = DocumentsV2ReadResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 422: + response_422 = cast(Any, None) + return response_422 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsV2ReadResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + draft_identifier: str, + *, + client: AuthenticatedClient | Client, + pretty: DocumentsV2GetDraftPretty | Unset = UNSET, +) -> Response[Any | DocumentsV2ReadResponse]: + r"""Read draft state + + Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape — same as the live- + state read endpoint. + + The response is structured so a caller can take it verbatim and submit it as the body of the draft + PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, + `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need + to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` + values also round-trip unchanged. + + Args: + identifier (str): Published document identifier. Example: abc123. + draft_identifier (str): Draft workbook identifier (see `POST + /api/v1/documents/{identifier}/draft`). Example: def456. + pretty (DocumentsV2GetDraftPretty | Unset): Set `true` or `1` to pretty-print (2-space + indent) the response; `false` / `0` (the default) is compact. Key ordering is + deterministic regardless. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2ReadResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + draft_identifier=draft_identifier, + pretty=pretty, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + draft_identifier: str, + *, + client: AuthenticatedClient | Client, + pretty: DocumentsV2GetDraftPretty | Unset = UNSET, +) -> Any | DocumentsV2ReadResponse | None: + r"""Read draft state + + Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape — same as the live- + state read endpoint. + + The response is structured so a caller can take it verbatim and submit it as the body of the draft + PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, + `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need + to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` + values also round-trip unchanged. + + Args: + identifier (str): Published document identifier. Example: abc123. + draft_identifier (str): Draft workbook identifier (see `POST + /api/v1/documents/{identifier}/draft`). Example: def456. + pretty (DocumentsV2GetDraftPretty | Unset): Set `true` or `1` to pretty-print (2-space + indent) the response; `false` / `0` (the default) is compact. Key ordering is + deterministic regardless. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2ReadResponse + """ + + return sync_detailed( + identifier=identifier, + draft_identifier=draft_identifier, + client=client, + pretty=pretty, + ).parsed + + +async def asyncio_detailed( + identifier: str, + draft_identifier: str, + *, + client: AuthenticatedClient | Client, + pretty: DocumentsV2GetDraftPretty | Unset = UNSET, +) -> Response[Any | DocumentsV2ReadResponse]: + r"""Read draft state + + Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape — same as the live- + state read endpoint. + + The response is structured so a caller can take it verbatim and submit it as the body of the draft + PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, + `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need + to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` + values also round-trip unchanged. + + Args: + identifier (str): Published document identifier. Example: abc123. + draft_identifier (str): Draft workbook identifier (see `POST + /api/v1/documents/{identifier}/draft`). Example: def456. + pretty (DocumentsV2GetDraftPretty | Unset): Set `true` or `1` to pretty-print (2-space + indent) the response; `false` / `0` (the default) is compact. Key ordering is + deterministic regardless. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2ReadResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + draft_identifier=draft_identifier, + pretty=pretty, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + draft_identifier: str, + *, + client: AuthenticatedClient | Client, + pretty: DocumentsV2GetDraftPretty | Unset = UNSET, +) -> Any | DocumentsV2ReadResponse | None: + r"""Read draft state + + Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape — same as the live- + state read endpoint. + + The response is structured so a caller can take it verbatim and submit it as the body of the draft + PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, + `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need + to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` + values also round-trip unchanged. + + Args: + identifier (str): Published document identifier. Example: abc123. + draft_identifier (str): Draft workbook identifier (see `POST + /api/v1/documents/{identifier}/draft`). Example: def456. + pretty (DocumentsV2GetDraftPretty | Unset): Set `true` or `1` to pretty-print (2-space + indent) the response; `false` / `0` (the default) is compact. Key ordering is + deterministic regardless. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2ReadResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + draft_identifier=draft_identifier, + client=client, + pretty=pretty, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_v2_patch_draft.py b/omni_python_sdk/api/documents/documents_v2_patch_draft.py new file mode 100644 index 0000000..e22fd69 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_v2_patch_draft.py @@ -0,0 +1,233 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_v2_create_draft_body import DocumentsV2CreateDraftBody +from ...models.documents_v2_patch_draft_response import DocumentsV2PatchDraftResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsV2CreateDraftBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v2/documents/{identifier}/draft".format( + identifier=quote(str(identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsV2PatchDraftResponse | None: + if response.status_code == 200: + response_200 = DocumentsV2PatchDraftResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if response.status_code == 422: + response_422 = cast(Any, None) + return response_422 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsV2PatchDraftResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsV2CreateDraftBody | Unset = UNSET, +) -> Response[Any | DocumentsV2PatchDraftResponse]: + """Create draft and patch document + + Create a new draft on the published document and apply the patch. No auto-publish — the response + includes the new `draftIdentifier` for follow-up calls. + + Pass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main + (unpublished) workspace. + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + body (DocumentsV2CreateDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2PatchDraftResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsV2CreateDraftBody | Unset = UNSET, +) -> Any | DocumentsV2PatchDraftResponse | None: + """Create draft and patch document + + Create a new draft on the published document and apply the patch. No auto-publish — the response + includes the new `draftIdentifier` for follow-up calls. + + Pass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main + (unpublished) workspace. + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + body (DocumentsV2CreateDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2PatchDraftResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsV2CreateDraftBody | Unset = UNSET, +) -> Response[Any | DocumentsV2PatchDraftResponse]: + """Create draft and patch document + + Create a new draft on the published document and apply the patch. No auto-publish — the response + includes the new `draftIdentifier` for follow-up calls. + + Pass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main + (unpublished) workspace. + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + body (DocumentsV2CreateDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2PatchDraftResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsV2CreateDraftBody | Unset = UNSET, +) -> Any | DocumentsV2PatchDraftResponse | None: + """Create draft and patch document + + Create a new draft on the published document and apply the patch. No auto-publish — the response + includes the new `draftIdentifier` for follow-up calls. + + Pass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main + (unpublished) workspace. + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + body (DocumentsV2CreateDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2PatchDraftResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_v2_patch_draft_by_identifier.py b/omni_python_sdk/api/documents/documents_v2_patch_draft_by_identifier.py new file mode 100644 index 0000000..5bc2f6d --- /dev/null +++ b/omni_python_sdk/api/documents/documents_v2_patch_draft_by_identifier.py @@ -0,0 +1,235 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_v2_patch_draft_body import DocumentsV2PatchDraftBody +from ...models.documents_v2_patch_draft_response import DocumentsV2PatchDraftResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + identifier: str, + draft_identifier: str, + *, + body: DocumentsV2PatchDraftBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v2/documents/{identifier}/draft/{draft_identifier}".format( + identifier=quote(str(identifier), safe=""), + draft_identifier=quote(str(draft_identifier), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsV2PatchDraftResponse | None: + if response.status_code == 200: + response_200 = DocumentsV2PatchDraftResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if response.status_code == 422: + response_422 = cast(Any, None) + return response_422 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsV2PatchDraftResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + draft_identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsV2PatchDraftBody | Unset = UNSET, +) -> Response[Any | DocumentsV2PatchDraftResponse]: + """Patch draft + + Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply — no draft creation, + no publish. + + Args: + identifier (str): Published document identifier. Example: abc123. + draft_identifier (str): Draft workbook identifier (see `POST + /api/v1/documents/{identifier}/draft`). Example: def456. + body (DocumentsV2PatchDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2PatchDraftResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + draft_identifier=draft_identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + draft_identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsV2PatchDraftBody | Unset = UNSET, +) -> Any | DocumentsV2PatchDraftResponse | None: + """Patch draft + + Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply — no draft creation, + no publish. + + Args: + identifier (str): Published document identifier. Example: abc123. + draft_identifier (str): Draft workbook identifier (see `POST + /api/v1/documents/{identifier}/draft`). Example: def456. + body (DocumentsV2PatchDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2PatchDraftResponse + """ + + return sync_detailed( + identifier=identifier, + draft_identifier=draft_identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + draft_identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsV2PatchDraftBody | Unset = UNSET, +) -> Response[Any | DocumentsV2PatchDraftResponse]: + """Patch draft + + Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply — no draft creation, + no publish. + + Args: + identifier (str): Published document identifier. Example: abc123. + draft_identifier (str): Draft workbook identifier (see `POST + /api/v1/documents/{identifier}/draft`). Example: def456. + body (DocumentsV2PatchDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2PatchDraftResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + draft_identifier=draft_identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + draft_identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsV2PatchDraftBody | Unset = UNSET, +) -> Any | DocumentsV2PatchDraftResponse | None: + """Patch draft + + Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply — no draft creation, + no publish. + + Args: + identifier (str): Published document identifier. Example: abc123. + draft_identifier (str): Draft workbook identifier (see `POST + /api/v1/documents/{identifier}/draft`). Example: def456. + body (DocumentsV2PatchDraftBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2PatchDraftResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + draft_identifier=draft_identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_v2_publish_draft.py b/omni_python_sdk/api/documents/documents_v2_publish_draft.py new file mode 100644 index 0000000..fae7477 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_v2_publish_draft.py @@ -0,0 +1,211 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_v2_publish_draft_response import DocumentsV2PublishDraftResponse +from ...types import Response + + +def _get_kwargs( + identifier: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v2/documents/{identifier}/draft/publish".format( + identifier=quote(str(identifier), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsV2PublishDraftResponse | None: + if response.status_code == 200: + response_200 = DocumentsV2PublishDraftResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsV2PublishDraftResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | DocumentsV2PublishDraftResponse]: + """Publish draft + + Publish the document's current main (non-branch) draft, promoting it to the published version. No + request body — the draft is consumed, so the response echoes the now-published document metadata. + + Only the main draft is publishable here; a branch-attached draft is published by merging its branch + (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft + returns 404. Documents that require a pull request to publish return 400. + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2PublishDraftResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Any | DocumentsV2PublishDraftResponse | None: + """Publish draft + + Publish the document's current main (non-branch) draft, promoting it to the published version. No + request body — the draft is consumed, so the response echoes the now-published document metadata. + + Only the main draft is publishable here; a branch-attached draft is published by merging its branch + (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft + returns 404. Documents that require a pull request to publish return 400. + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2PublishDraftResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | DocumentsV2PublishDraftResponse]: + """Publish draft + + Publish the document's current main (non-branch) draft, promoting it to the published version. No + request body — the draft is consumed, so the response echoes the now-published document metadata. + + Only the main draft is publishable here; a branch-attached draft is published by merging its branch + (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft + returns 404. Documents that require a pull request to publish return 400. + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2PublishDraftResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Any | DocumentsV2PublishDraftResponse | None: + """Publish draft + + Publish the document's current main (non-branch) draft, promoting it to the published version. No + request body — the draft is consumed, so the response echoes the now-published document metadata. + + Only the main draft is publishable here; a branch-attached draft is published by merging its branch + (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft + returns 404. Documents that require a pull request to publish return 400. + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2PublishDraftResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/documents/documents_v2_update_identifier.py b/omni_python_sdk/api/documents/documents_v2_update_identifier.py new file mode 100644 index 0000000..e972ba4 --- /dev/null +++ b/omni_python_sdk/api/documents/documents_v2_update_identifier.py @@ -0,0 +1,236 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_v2_update_identifier_body import DocumentsV2UpdateIdentifierBody +from ...models.documents_v2_update_identifier_response import DocumentsV2UpdateIdentifierResponse +from ...types import Response + + +def _get_kwargs( + identifier: str, + *, + body: DocumentsV2UpdateIdentifierBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v2/documents/{identifier}/identifier".format( + identifier=quote(str(identifier), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsV2UpdateIdentifierResponse | None: + if response.status_code == 200: + response_200 = DocumentsV2UpdateIdentifierResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsV2UpdateIdentifierResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsV2UpdateIdentifierBody, +) -> Response[Any | DocumentsV2UpdateIdentifierResponse]: + """Rename document identifier + + Rename a published document's identifier. The change is applied live and immediately — it does not + go through the draft/publish workflow — and the former identifier is recorded in the document's + rename history. + + Only published documents can be renamed. A draft target returns 409; an unknown or archived target + returns 404. The new identifier must be a valid slug (otherwise 400) and unused by any other + document in the organization (otherwise 409). + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + body (DocumentsV2UpdateIdentifierBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2UpdateIdentifierResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsV2UpdateIdentifierBody, +) -> Any | DocumentsV2UpdateIdentifierResponse | None: + """Rename document identifier + + Rename a published document's identifier. The change is applied live and immediately — it does not + go through the draft/publish workflow — and the former identifier is recorded in the document's + rename history. + + Only published documents can be renamed. A draft target returns 409; an unknown or archived target + returns 404. The new identifier must be a valid slug (otherwise 400) and unused by any other + document in the organization (otherwise 409). + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + body (DocumentsV2UpdateIdentifierBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2UpdateIdentifierResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsV2UpdateIdentifierBody, +) -> Response[Any | DocumentsV2UpdateIdentifierResponse]: + """Rename document identifier + + Rename a published document's identifier. The change is applied live and immediately — it does not + go through the draft/publish workflow — and the former identifier is recorded in the document's + rename history. + + Only published documents can be renamed. A draft target returns 409; an unknown or archived target + returns 404. The new identifier must be a valid slug (otherwise 400) and unused by any other + document in the organization (otherwise 409). + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + body (DocumentsV2UpdateIdentifierBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2UpdateIdentifierResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, + body: DocumentsV2UpdateIdentifierBody, +) -> Any | DocumentsV2UpdateIdentifierResponse | None: + """Rename document identifier + + Rename a published document's identifier. The change is applied live and immediately — it does not + go through the draft/publish workflow — and the former identifier is recorded in the document's + rename history. + + Only published documents can be renamed. A draft target returns 409; an unknown or archived target + returns 404. The new identifier must be a valid slug (otherwise 400) and unused by any other + document in the organization (otherwise 409). + + Args: + identifier (str): Document identifier — either the URL slug (e.g. `abc123`) or the + canonical workbook UUID. Example: abc123. + body (DocumentsV2UpdateIdentifierBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2UpdateIdentifierResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/embed/__init__.py b/omni_python_sdk/api/embed/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/embed/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/embed/embed_sso_generate_session.py b/omni_python_sdk/api/embed/embed_sso_generate_session.py new file mode 100644 index 0000000..aaa6912 --- /dev/null +++ b/omni_python_sdk/api/embed/embed_sso_generate_session.py @@ -0,0 +1,173 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.embed_sso_generate_session_body import EmbedSsoGenerateSessionBody +from ...models.embed_sso_generate_session_response import EmbedSsoGenerateSessionResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: EmbedSsoGenerateSessionBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/embed/sso/generate-session", + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | EmbedSsoGenerateSessionResponse | None: + if response.status_code == 200: + response_200 = EmbedSsoGenerateSessionResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | EmbedSsoGenerateSessionResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: EmbedSsoGenerateSessionBody | Unset = UNSET, +) -> Response[Any | EmbedSsoGenerateSessionResponse]: + """Generate embedded SSO session + + Args: + body (EmbedSsoGenerateSessionBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | EmbedSsoGenerateSessionResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: EmbedSsoGenerateSessionBody | Unset = UNSET, +) -> Any | EmbedSsoGenerateSessionResponse | None: + """Generate embedded SSO session + + Args: + body (EmbedSsoGenerateSessionBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | EmbedSsoGenerateSessionResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: EmbedSsoGenerateSessionBody | Unset = UNSET, +) -> Response[Any | EmbedSsoGenerateSessionResponse]: + """Generate embedded SSO session + + Args: + body (EmbedSsoGenerateSessionBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | EmbedSsoGenerateSessionResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: EmbedSsoGenerateSessionBody | Unset = UNSET, +) -> Any | EmbedSsoGenerateSessionResponse | None: + """Generate embedded SSO session + + Args: + body (EmbedSsoGenerateSessionBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | EmbedSsoGenerateSessionResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/folders/__init__.py b/omni_python_sdk/api/folders/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/folders/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/folders/folders_add_permissions.py b/omni_python_sdk/api/folders/folders_add_permissions.py new file mode 100644 index 0000000..a1fcbe2 --- /dev/null +++ b/omni_python_sdk/api/folders/folders_add_permissions.py @@ -0,0 +1,198 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.folders_add_permissions_body import FoldersAddPermissionsBody +from ...models.folders_add_permissions_response import FoldersAddPermissionsResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + folder_id: UUID, + *, + body: FoldersAddPermissionsBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/folders/{folder_id}/permissions".format( + folder_id=quote(str(folder_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | FoldersAddPermissionsResponse | None: + if response.status_code == 200: + response_200 = FoldersAddPermissionsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | FoldersAddPermissionsResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersAddPermissionsBody | Unset = UNSET, +) -> Response[Any | FoldersAddPermissionsResponse]: + """Add folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersAddPermissionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersAddPermissionsResponse] + """ + + kwargs = _get_kwargs( + folder_id=folder_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersAddPermissionsBody | Unset = UNSET, +) -> Any | FoldersAddPermissionsResponse | None: + """Add folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersAddPermissionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersAddPermissionsResponse + """ + + return sync_detailed( + folder_id=folder_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersAddPermissionsBody | Unset = UNSET, +) -> Response[Any | FoldersAddPermissionsResponse]: + """Add folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersAddPermissionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersAddPermissionsResponse] + """ + + kwargs = _get_kwargs( + folder_id=folder_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersAddPermissionsBody | Unset = UNSET, +) -> Any | FoldersAddPermissionsResponse | None: + """Add folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersAddPermissionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersAddPermissionsResponse + """ + + return ( + await asyncio_detailed( + folder_id=folder_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/folders/folders_create.py b/omni_python_sdk/api/folders/folders_create.py new file mode 100644 index 0000000..753579a --- /dev/null +++ b/omni_python_sdk/api/folders/folders_create.py @@ -0,0 +1,173 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.folders_create_body import FoldersCreateBody +from ...models.folders_create_response import FoldersCreateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: FoldersCreateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/folders", + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | FoldersCreateResponse | None: + if response.status_code == 201: + response_201 = FoldersCreateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | FoldersCreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: FoldersCreateBody | Unset = UNSET, +) -> Response[Any | FoldersCreateResponse]: + """Create a folder + + Args: + body (FoldersCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: FoldersCreateBody | Unset = UNSET, +) -> Any | FoldersCreateResponse | None: + """Create a folder + + Args: + body (FoldersCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersCreateResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: FoldersCreateBody | Unset = UNSET, +) -> Response[Any | FoldersCreateResponse]: + """Create a folder + + Args: + body (FoldersCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: FoldersCreateBody | Unset = UNSET, +) -> Any | FoldersCreateResponse | None: + """Create a folder + + Args: + body (FoldersCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersCreateResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/folders/folders_delete.py b/omni_python_sdk/api/folders/folders_delete.py new file mode 100644 index 0000000..8d1e267 --- /dev/null +++ b/omni_python_sdk/api/folders/folders_delete.py @@ -0,0 +1,230 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.folders_delete_response import FoldersDeleteResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + folder_id: UUID, + *, + force: bool | None | Unset = False, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_force: bool | None | Unset + if isinstance(force, Unset): + json_force = UNSET + else: + json_force = force + params["force"] = json_force + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/folders/{folder_id}".format( + folder_id=quote(str(folder_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | FoldersDeleteResponse | None: + if response.status_code == 200: + response_200 = FoldersDeleteResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | FoldersDeleteResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + force: bool | None | Unset = False, +) -> Response[Any | FoldersDeleteResponse]: + """Delete a folder + + Deletes a folder. By default, non-empty folders (containing documents or sub-folders) return a 400 + error. Pass `force=true` to recursively archive all documents (soft-delete to trash) and permanently + remove all sub-folders before deleting the target folder. Force delete is limited to 100 total items + (documents + sub-folders). + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + force (bool | None | Unset): When true, recursively deletes all documents (sent to trash) + and sub-folders within the folder. Limited to 100 total items (documents + sub-folders). + Default: False. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersDeleteResponse] + """ + + kwargs = _get_kwargs( + folder_id=folder_id, + force=force, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + force: bool | None | Unset = False, +) -> Any | FoldersDeleteResponse | None: + """Delete a folder + + Deletes a folder. By default, non-empty folders (containing documents or sub-folders) return a 400 + error. Pass `force=true` to recursively archive all documents (soft-delete to trash) and permanently + remove all sub-folders before deleting the target folder. Force delete is limited to 100 total items + (documents + sub-folders). + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + force (bool | None | Unset): When true, recursively deletes all documents (sent to trash) + and sub-folders within the folder. Limited to 100 total items (documents + sub-folders). + Default: False. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersDeleteResponse + """ + + return sync_detailed( + folder_id=folder_id, + client=client, + force=force, + ).parsed + + +async def asyncio_detailed( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + force: bool | None | Unset = False, +) -> Response[Any | FoldersDeleteResponse]: + """Delete a folder + + Deletes a folder. By default, non-empty folders (containing documents or sub-folders) return a 400 + error. Pass `force=true` to recursively archive all documents (soft-delete to trash) and permanently + remove all sub-folders before deleting the target folder. Force delete is limited to 100 total items + (documents + sub-folders). + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + force (bool | None | Unset): When true, recursively deletes all documents (sent to trash) + and sub-folders within the folder. Limited to 100 total items (documents + sub-folders). + Default: False. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersDeleteResponse] + """ + + kwargs = _get_kwargs( + folder_id=folder_id, + force=force, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + force: bool | None | Unset = False, +) -> Any | FoldersDeleteResponse | None: + """Delete a folder + + Deletes a folder. By default, non-empty folders (containing documents or sub-folders) return a 400 + error. Pass `force=true` to recursively archive all documents (soft-delete to trash) and permanently + remove all sub-folders before deleting the target folder. Force delete is limited to 100 total items + (documents + sub-folders). + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + force (bool | None | Unset): When true, recursively deletes all documents (sent to trash) + and sub-folders within the folder. Limited to 100 total items (documents + sub-folders). + Default: False. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersDeleteResponse + """ + + return ( + await asyncio_detailed( + folder_id=folder_id, + client=client, + force=force, + ) + ).parsed diff --git a/omni_python_sdk/api/folders/folders_get_permissions.py b/omni_python_sdk/api/folders/folders_get_permissions.py new file mode 100644 index 0000000..9c42065 --- /dev/null +++ b/omni_python_sdk/api/folders/folders_get_permissions.py @@ -0,0 +1,200 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.folders_get_permissions_response import FoldersGetPermissionsResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + folder_id: UUID, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/folders/{folder_id}/permissions".format( + folder_id=quote(str(folder_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | FoldersGetPermissionsResponse | None: + if response.status_code == 200: + response_200 = FoldersGetPermissionsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | FoldersGetPermissionsResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any | FoldersGetPermissionsResponse]: + """Get folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + user_id (UUID | Unset): Filter permits for a specific user. If omitted, returns all + permits (requires MANAGER role). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersGetPermissionsResponse] + """ + + kwargs = _get_kwargs( + folder_id=folder_id, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Any | FoldersGetPermissionsResponse | None: + """Get folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + user_id (UUID | Unset): Filter permits for a specific user. If omitted, returns all + permits (requires MANAGER role). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersGetPermissionsResponse + """ + + return sync_detailed( + folder_id=folder_id, + client=client, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any | FoldersGetPermissionsResponse]: + """Get folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + user_id (UUID | Unset): Filter permits for a specific user. If omitted, returns all + permits (requires MANAGER role). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersGetPermissionsResponse] + """ + + kwargs = _get_kwargs( + folder_id=folder_id, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Any | FoldersGetPermissionsResponse | None: + """Get folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + user_id (UUID | Unset): Filter permits for a specific user. If omitted, returns all + permits (requires MANAGER role). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersGetPermissionsResponse + """ + + return ( + await asyncio_detailed( + folder_id=folder_id, + client=client, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/folders/folders_list.py b/omni_python_sdk/api/folders/folders_list.py new file mode 100644 index 0000000..7da2d68 --- /dev/null +++ b/omni_python_sdk/api/folders/folders_list.py @@ -0,0 +1,350 @@ +from http import HTTPStatus +from typing import Any, cast +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.folders_list_response import FoldersListResponse +from ...models.folders_list_scope import FoldersListScope +from ...models.folders_list_sort_direction import FoldersListSortDirection +from ...models.folders_list_sort_field import FoldersListSortField +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + cursor: str | Unset = UNSET, + include: str | Unset = UNSET, + labels: str | Unset = UNSET, + owner_id: UUID | Unset = UNSET, + page_size: float | None | Unset = UNSET, + path: str | Unset = UNSET, + scope: FoldersListScope | Unset = UNSET, + sort_direction: FoldersListSortDirection | Unset = UNSET, + sort_field: FoldersListSortField | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["include"] = include + + params["labels"] = labels + + json_owner_id: str | Unset = UNSET + if not isinstance(owner_id, Unset): + json_owner_id = str(owner_id) + params["ownerId"] = json_owner_id + + json_page_size: float | None | Unset + if isinstance(page_size, Unset): + json_page_size = UNSET + else: + json_page_size = page_size + params["pageSize"] = json_page_size + + params["path"] = path + + json_scope: str | Unset = UNSET + if not isinstance(scope, Unset): + json_scope = scope + + params["scope"] = json_scope + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + json_sort_field: str | Unset = UNSET + if not isinstance(sort_field, Unset): + json_sort_field = sort_field + + params["sortField"] = json_sort_field + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/folders", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | FoldersListResponse | None: + if response.status_code == 200: + response_200 = FoldersListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | FoldersListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + include: str | Unset = UNSET, + labels: str | Unset = UNSET, + owner_id: UUID | Unset = UNSET, + page_size: float | None | Unset = UNSET, + path: str | Unset = UNSET, + scope: FoldersListScope | Unset = UNSET, + sort_direction: FoldersListSortDirection | Unset = UNSET, + sort_field: FoldersListSortField | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | FoldersListResponse]: + """List folders + + Args: + cursor (str | Unset): Cursor for pagination + include (str | Unset): Comma-separated list of fields to include (_count, labels, + onlySharedWithMe). onlySharedWithMe returns only folders shared with the user, cannot be + combined with ownerId or path, and when used with org-scoped API keys requires the userId + query parameter. For user-scoped keys (PAT), userId is auto-inferred from the token. + Example: _count,labels. + labels (str | Unset): Comma-separated list of labels to filter by + owner_id (UUID | Unset): Filter by owner user ID + page_size (float | None | Unset): Number of results per page Example: 20. + path (str | Unset): Filter by exact path + scope (FoldersListScope | Unset): Filter by share scope + sort_direction (FoldersListSortDirection | Unset): Sort direction + sort_field (FoldersListSortField | Unset): Field to sort by + user_id (UUID | Unset): User membership ID. Only used with onlySharedWithMe include field. + Required for org-scoped API keys; auto-inferred from the token for user-scoped keys (PAT). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersListResponse] + """ + + kwargs = _get_kwargs( + cursor=cursor, + include=include, + labels=labels, + owner_id=owner_id, + page_size=page_size, + path=path, + scope=scope, + sort_direction=sort_direction, + sort_field=sort_field, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + include: str | Unset = UNSET, + labels: str | Unset = UNSET, + owner_id: UUID | Unset = UNSET, + page_size: float | None | Unset = UNSET, + path: str | Unset = UNSET, + scope: FoldersListScope | Unset = UNSET, + sort_direction: FoldersListSortDirection | Unset = UNSET, + sort_field: FoldersListSortField | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | FoldersListResponse | None: + """List folders + + Args: + cursor (str | Unset): Cursor for pagination + include (str | Unset): Comma-separated list of fields to include (_count, labels, + onlySharedWithMe). onlySharedWithMe returns only folders shared with the user, cannot be + combined with ownerId or path, and when used with org-scoped API keys requires the userId + query parameter. For user-scoped keys (PAT), userId is auto-inferred from the token. + Example: _count,labels. + labels (str | Unset): Comma-separated list of labels to filter by + owner_id (UUID | Unset): Filter by owner user ID + page_size (float | None | Unset): Number of results per page Example: 20. + path (str | Unset): Filter by exact path + scope (FoldersListScope | Unset): Filter by share scope + sort_direction (FoldersListSortDirection | Unset): Sort direction + sort_field (FoldersListSortField | Unset): Field to sort by + user_id (UUID | Unset): User membership ID. Only used with onlySharedWithMe include field. + Required for org-scoped API keys; auto-inferred from the token for user-scoped keys (PAT). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersListResponse + """ + + return sync_detailed( + client=client, + cursor=cursor, + include=include, + labels=labels, + owner_id=owner_id, + page_size=page_size, + path=path, + scope=scope, + sort_direction=sort_direction, + sort_field=sort_field, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + include: str | Unset = UNSET, + labels: str | Unset = UNSET, + owner_id: UUID | Unset = UNSET, + page_size: float | None | Unset = UNSET, + path: str | Unset = UNSET, + scope: FoldersListScope | Unset = UNSET, + sort_direction: FoldersListSortDirection | Unset = UNSET, + sort_field: FoldersListSortField | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | FoldersListResponse]: + """List folders + + Args: + cursor (str | Unset): Cursor for pagination + include (str | Unset): Comma-separated list of fields to include (_count, labels, + onlySharedWithMe). onlySharedWithMe returns only folders shared with the user, cannot be + combined with ownerId or path, and when used with org-scoped API keys requires the userId + query parameter. For user-scoped keys (PAT), userId is auto-inferred from the token. + Example: _count,labels. + labels (str | Unset): Comma-separated list of labels to filter by + owner_id (UUID | Unset): Filter by owner user ID + page_size (float | None | Unset): Number of results per page Example: 20. + path (str | Unset): Filter by exact path + scope (FoldersListScope | Unset): Filter by share scope + sort_direction (FoldersListSortDirection | Unset): Sort direction + sort_field (FoldersListSortField | Unset): Field to sort by + user_id (UUID | Unset): User membership ID. Only used with onlySharedWithMe include field. + Required for org-scoped API keys; auto-inferred from the token for user-scoped keys (PAT). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersListResponse] + """ + + kwargs = _get_kwargs( + cursor=cursor, + include=include, + labels=labels, + owner_id=owner_id, + page_size=page_size, + path=path, + scope=scope, + sort_direction=sort_direction, + sort_field=sort_field, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + include: str | Unset = UNSET, + labels: str | Unset = UNSET, + owner_id: UUID | Unset = UNSET, + page_size: float | None | Unset = UNSET, + path: str | Unset = UNSET, + scope: FoldersListScope | Unset = UNSET, + sort_direction: FoldersListSortDirection | Unset = UNSET, + sort_field: FoldersListSortField | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | FoldersListResponse | None: + """List folders + + Args: + cursor (str | Unset): Cursor for pagination + include (str | Unset): Comma-separated list of fields to include (_count, labels, + onlySharedWithMe). onlySharedWithMe returns only folders shared with the user, cannot be + combined with ownerId or path, and when used with org-scoped API keys requires the userId + query parameter. For user-scoped keys (PAT), userId is auto-inferred from the token. + Example: _count,labels. + labels (str | Unset): Comma-separated list of labels to filter by + owner_id (UUID | Unset): Filter by owner user ID + page_size (float | None | Unset): Number of results per page Example: 20. + path (str | Unset): Filter by exact path + scope (FoldersListScope | Unset): Filter by share scope + sort_direction (FoldersListSortDirection | Unset): Sort direction + sort_field (FoldersListSortField | Unset): Field to sort by + user_id (UUID | Unset): User membership ID. Only used with onlySharedWithMe include field. + Required for org-scoped API keys; auto-inferred from the token for user-scoped keys (PAT). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersListResponse + """ + + return ( + await asyncio_detailed( + client=client, + cursor=cursor, + include=include, + labels=labels, + owner_id=owner_id, + page_size=page_size, + path=path, + scope=scope, + sort_direction=sort_direction, + sort_field=sort_field, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/folders/folders_revoke_permissions.py b/omni_python_sdk/api/folders/folders_revoke_permissions.py new file mode 100644 index 0000000..921ca99 --- /dev/null +++ b/omni_python_sdk/api/folders/folders_revoke_permissions.py @@ -0,0 +1,198 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.folders_revoke_permissions_body import FoldersRevokePermissionsBody +from ...models.folders_revoke_permissions_response import FoldersRevokePermissionsResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + folder_id: UUID, + *, + body: FoldersRevokePermissionsBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/folders/{folder_id}/permissions".format( + folder_id=quote(str(folder_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | FoldersRevokePermissionsResponse | None: + if response.status_code == 200: + response_200 = FoldersRevokePermissionsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | FoldersRevokePermissionsResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersRevokePermissionsBody | Unset = UNSET, +) -> Response[Any | FoldersRevokePermissionsResponse]: + """Revoke folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersRevokePermissionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersRevokePermissionsResponse] + """ + + kwargs = _get_kwargs( + folder_id=folder_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersRevokePermissionsBody | Unset = UNSET, +) -> Any | FoldersRevokePermissionsResponse | None: + """Revoke folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersRevokePermissionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersRevokePermissionsResponse + """ + + return sync_detailed( + folder_id=folder_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersRevokePermissionsBody | Unset = UNSET, +) -> Response[Any | FoldersRevokePermissionsResponse]: + """Revoke folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersRevokePermissionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersRevokePermissionsResponse] + """ + + kwargs = _get_kwargs( + folder_id=folder_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersRevokePermissionsBody | Unset = UNSET, +) -> Any | FoldersRevokePermissionsResponse | None: + """Revoke folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersRevokePermissionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersRevokePermissionsResponse + """ + + return ( + await asyncio_detailed( + folder_id=folder_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/folders/folders_update.py b/omni_python_sdk/api/folders/folders_update.py new file mode 100644 index 0000000..090f636 --- /dev/null +++ b/omni_python_sdk/api/folders/folders_update.py @@ -0,0 +1,218 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.folders_update_body import FoldersUpdateBody +from ...models.folders_update_response import FoldersUpdateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + folder_id: UUID, + *, + body: FoldersUpdateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/folders/{folder_id}".format( + folder_id=quote(str(folder_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | FoldersUpdateResponse | None: + if response.status_code == 200: + response_200 = FoldersUpdateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | FoldersUpdateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersUpdateBody | Unset = UNSET, +) -> Response[Any | FoldersUpdateResponse]: + """Update a folder + + Update a folder's display name and/or URL path segment. At least one of `name` or `path` must be + provided. Changing the name does not automatically update the path. When the path is updated, + descendant folder paths are cascaded. + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersUpdateResponse] + """ + + kwargs = _get_kwargs( + folder_id=folder_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersUpdateBody | Unset = UNSET, +) -> Any | FoldersUpdateResponse | None: + """Update a folder + + Update a folder's display name and/or URL path segment. At least one of `name` or `path` must be + provided. Changing the name does not automatically update the path. When the path is updated, + descendant folder paths are cascaded. + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersUpdateResponse + """ + + return sync_detailed( + folder_id=folder_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersUpdateBody | Unset = UNSET, +) -> Response[Any | FoldersUpdateResponse]: + """Update a folder + + Update a folder's display name and/or URL path segment. At least one of `name` or `path` must be + provided. Changing the name does not automatically update the path. When the path is updated, + descendant folder paths are cascaded. + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersUpdateResponse] + """ + + kwargs = _get_kwargs( + folder_id=folder_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersUpdateBody | Unset = UNSET, +) -> Any | FoldersUpdateResponse | None: + """Update a folder + + Update a folder's display name and/or URL path segment. At least one of `name` or `path` must be + provided. Changing the name does not automatically update the path. When the path is updated, + descendant folder paths are cascaded. + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersUpdateResponse + """ + + return ( + await asyncio_detailed( + folder_id=folder_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/folders/folders_update_permissions.py b/omni_python_sdk/api/folders/folders_update_permissions.py new file mode 100644 index 0000000..2c1c51f --- /dev/null +++ b/omni_python_sdk/api/folders/folders_update_permissions.py @@ -0,0 +1,198 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.folders_update_permissions_body import FoldersUpdatePermissionsBody +from ...models.folders_update_permissions_response import FoldersUpdatePermissionsResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + folder_id: UUID, + *, + body: FoldersUpdatePermissionsBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/folders/{folder_id}/permissions".format( + folder_id=quote(str(folder_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | FoldersUpdatePermissionsResponse | None: + if response.status_code == 200: + response_200 = FoldersUpdatePermissionsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | FoldersUpdatePermissionsResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersUpdatePermissionsBody | Unset = UNSET, +) -> Response[Any | FoldersUpdatePermissionsResponse]: + """Update folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersUpdatePermissionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersUpdatePermissionsResponse] + """ + + kwargs = _get_kwargs( + folder_id=folder_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersUpdatePermissionsBody | Unset = UNSET, +) -> Any | FoldersUpdatePermissionsResponse | None: + """Update folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersUpdatePermissionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersUpdatePermissionsResponse + """ + + return sync_detailed( + folder_id=folder_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersUpdatePermissionsBody | Unset = UNSET, +) -> Response[Any | FoldersUpdatePermissionsResponse]: + """Update folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersUpdatePermissionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | FoldersUpdatePermissionsResponse] + """ + + kwargs = _get_kwargs( + folder_id=folder_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + folder_id: UUID, + *, + client: AuthenticatedClient | Client, + body: FoldersUpdatePermissionsBody | Unset = UNSET, +) -> Any | FoldersUpdatePermissionsResponse | None: + """Update folder permissions + + Args: + folder_id (UUID): Unique identifier for the folder Example: + 550e8400-e29b-41d4-a716-446655440000. + body (FoldersUpdatePermissionsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | FoldersUpdatePermissionsResponse + """ + + return ( + await asyncio_detailed( + folder_id=folder_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/labels/__init__.py b/omni_python_sdk/api/labels/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/labels/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/labels/labels_create.py b/omni_python_sdk/api/labels/labels_create.py new file mode 100644 index 0000000..fd96110 --- /dev/null +++ b/omni_python_sdk/api/labels/labels_create.py @@ -0,0 +1,201 @@ +from http import HTTPStatus +from typing import Any, cast +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.labels_create_body import LabelsCreateBody +from ...models.labels_create_response import LabelsCreateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: LabelsCreateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/labels", + "params": params, + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | LabelsCreateResponse | None: + if response.status_code == 201: + response_201 = LabelsCreateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | LabelsCreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: LabelsCreateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | LabelsCreateResponse]: + """Create a label + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (LabelsCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | LabelsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: LabelsCreateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | LabelsCreateResponse | None: + """Create a label + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (LabelsCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | LabelsCreateResponse + """ + + return sync_detailed( + client=client, + body=body, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: LabelsCreateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | LabelsCreateResponse]: + """Create a label + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (LabelsCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | LabelsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: LabelsCreateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | LabelsCreateResponse | None: + """Create a label + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (LabelsCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | LabelsCreateResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/labels/labels_delete.py b/omni_python_sdk/api/labels/labels_delete.py new file mode 100644 index 0000000..9e3449b --- /dev/null +++ b/omni_python_sdk/api/labels/labels_delete.py @@ -0,0 +1,129 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + name: str, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/labels/{name}".format( + name=quote(str(name), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None: + if response.status_code == 204: + return None + + if response.status_code == 401: + return None + + if response.status_code == 403: + return None + + if response.status_code == 404: + return None + + if response.status_code == 409: + return None + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + name: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Delete a label + + Args: + name (str): Label name Example: verified. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + name=name, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + name: str, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any]: + """Delete a label + + Args: + name (str): Label name Example: verified. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + name=name, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/omni_python_sdk/api/labels/labels_get.py b/omni_python_sdk/api/labels/labels_get.py new file mode 100644 index 0000000..d29e9a8 --- /dev/null +++ b/omni_python_sdk/api/labels/labels_get.py @@ -0,0 +1,163 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.labels_get_response import LabelsGetResponse +from ...types import Response + + +def _get_kwargs( + name: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/labels/{name}".format( + name=quote(str(name), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | LabelsGetResponse | None: + if response.status_code == 200: + response_200 = LabelsGetResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | LabelsGetResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + name: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | LabelsGetResponse]: + """Get a label by name + + Args: + name (str): Label name Example: verified. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | LabelsGetResponse] + """ + + kwargs = _get_kwargs( + name=name, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + name: str, + *, + client: AuthenticatedClient | Client, +) -> Any | LabelsGetResponse | None: + """Get a label by name + + Args: + name (str): Label name Example: verified. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | LabelsGetResponse + """ + + return sync_detailed( + name=name, + client=client, + ).parsed + + +async def asyncio_detailed( + name: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | LabelsGetResponse]: + """Get a label by name + + Args: + name (str): Label name Example: verified. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | LabelsGetResponse] + """ + + kwargs = _get_kwargs( + name=name, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + name: str, + *, + client: AuthenticatedClient | Client, +) -> Any | LabelsGetResponse | None: + """Get a label by name + + Args: + name (str): Label name Example: verified. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | LabelsGetResponse + """ + + return ( + await asyncio_detailed( + name=name, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/labels/labels_list.py b/omni_python_sdk/api/labels/labels_list.py new file mode 100644 index 0000000..7140674 --- /dev/null +++ b/omni_python_sdk/api/labels/labels_list.py @@ -0,0 +1,132 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.labels_list_response import LabelsListResponse +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/labels", + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | LabelsListResponse | None: + if response.status_code == 200: + response_200 = LabelsListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | LabelsListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, +) -> Response[Any | LabelsListResponse]: + """List all labels + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | LabelsListResponse] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, +) -> Any | LabelsListResponse | None: + """List all labels + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | LabelsListResponse + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, +) -> Response[Any | LabelsListResponse]: + """List all labels + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | LabelsListResponse] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, +) -> Any | LabelsListResponse | None: + """List all labels + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | LabelsListResponse + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/labels/labels_update.py b/omni_python_sdk/api/labels/labels_update.py new file mode 100644 index 0000000..ac7f868 --- /dev/null +++ b/omni_python_sdk/api/labels/labels_update.py @@ -0,0 +1,221 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.labels_update_body import LabelsUpdateBody +from ...models.labels_update_response import LabelsUpdateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + name: str, + *, + body: LabelsUpdateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/labels/{name}".format( + name=quote(str(name), safe=""), + ), + "params": params, + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | LabelsUpdateResponse | None: + if response.status_code == 200: + response_200 = LabelsUpdateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | LabelsUpdateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + name: str, + *, + client: AuthenticatedClient | Client, + body: LabelsUpdateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | LabelsUpdateResponse]: + """Update a label + + Args: + name (str): Label name Example: verified. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (LabelsUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | LabelsUpdateResponse] + """ + + kwargs = _get_kwargs( + name=name, + body=body, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + name: str, + *, + client: AuthenticatedClient | Client, + body: LabelsUpdateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | LabelsUpdateResponse | None: + """Update a label + + Args: + name (str): Label name Example: verified. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (LabelsUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | LabelsUpdateResponse + """ + + return sync_detailed( + name=name, + client=client, + body=body, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + name: str, + *, + client: AuthenticatedClient | Client, + body: LabelsUpdateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | LabelsUpdateResponse]: + """Update a label + + Args: + name (str): Label name Example: verified. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (LabelsUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | LabelsUpdateResponse] + """ + + kwargs = _get_kwargs( + name=name, + body=body, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + name: str, + *, + client: AuthenticatedClient | Client, + body: LabelsUpdateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | LabelsUpdateResponse | None: + """Update a label + + Args: + name (str): Label name Example: verified. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (LabelsUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | LabelsUpdateResponse + """ + + return ( + await asyncio_detailed( + name=name, + client=client, + body=body, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/models/__init__.py b/omni_python_sdk/api/models/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/models/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/models/jobs_get_status.py b/omni_python_sdk/api/models/jobs_get_status.py new file mode 100644 index 0000000..e6e3b6a --- /dev/null +++ b/omni_python_sdk/api/models/jobs_get_status.py @@ -0,0 +1,187 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.jobs_get_status_response import JobsGetStatusResponse +from ...types import Response + + +def _get_kwargs( + job_id: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/jobs/{job_id}/status".format( + job_id=quote(str(job_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | JobsGetStatusResponse | None: + if response.status_code == 200: + response_200 = JobsGetStatusResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | JobsGetStatusResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + job_id: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | JobsGetStatusResponse]: + """Get schema refresh or dbt sync job status + + Check status of a schema refresh job (POST /api/v1/models/{modelId}/refresh) or a dbt sync job (POST + /api/v1/models/{modelId}/dbt-sync). Returns IN_PROGRESS, COMPLETED, or FAILED. + + Args: + job_id (str): The job ID returned from a job creation endpoint (e.g., POST + /api/v1/models/{modelId}/refresh) Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | JobsGetStatusResponse] + """ + + kwargs = _get_kwargs( + job_id=job_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + job_id: str, + *, + client: AuthenticatedClient | Client, +) -> Any | JobsGetStatusResponse | None: + """Get schema refresh or dbt sync job status + + Check status of a schema refresh job (POST /api/v1/models/{modelId}/refresh) or a dbt sync job (POST + /api/v1/models/{modelId}/dbt-sync). Returns IN_PROGRESS, COMPLETED, or FAILED. + + Args: + job_id (str): The job ID returned from a job creation endpoint (e.g., POST + /api/v1/models/{modelId}/refresh) Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | JobsGetStatusResponse + """ + + return sync_detailed( + job_id=job_id, + client=client, + ).parsed + + +async def asyncio_detailed( + job_id: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | JobsGetStatusResponse]: + """Get schema refresh or dbt sync job status + + Check status of a schema refresh job (POST /api/v1/models/{modelId}/refresh) or a dbt sync job (POST + /api/v1/models/{modelId}/dbt-sync). Returns IN_PROGRESS, COMPLETED, or FAILED. + + Args: + job_id (str): The job ID returned from a job creation endpoint (e.g., POST + /api/v1/models/{modelId}/refresh) Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | JobsGetStatusResponse] + """ + + kwargs = _get_kwargs( + job_id=job_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + job_id: str, + *, + client: AuthenticatedClient | Client, +) -> Any | JobsGetStatusResponse | None: + """Get schema refresh or dbt sync job status + + Check status of a schema refresh job (POST /api/v1/models/{modelId}/refresh) or a dbt sync job (POST + /api/v1/models/{modelId}/dbt-sync). Returns IN_PROGRESS, COMPLETED, or FAILED. + + Args: + job_id (str): The job ID returned from a job creation endpoint (e.g., POST + /api/v1/models/{modelId}/refresh) Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | JobsGetStatusResponse + """ + + return ( + await asyncio_detailed( + job_id=job_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/models/model_ai_agent_actions.py b/omni_python_sdk/api/models/model_ai_agent_actions.py new file mode 100644 index 0000000..043d6db --- /dev/null +++ b/omni_python_sdk/api/models/model_ai_agent_actions.py @@ -0,0 +1,192 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_agent_actions_response import AiAgentActionsResponse +from ...types import Response + + +def _get_kwargs( + model_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/ai-agent-actions".format( + model_id=quote(str(model_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiAgentActionsResponse | Any | None: + if response.status_code == 200: + response_200 = AiAgentActionsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiAgentActionsResponse | Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[AiAgentActionsResponse | Any]: + """Get model AI agent actions + + Returns the AI agent actions configured for this model — a unified list of sample queries and skills + suitable for surfacing as suggested prompts above an AI prompt input. Sample queries come from both + `model.sample_queries` and each topic's `sample_queries`; skills come from `model.skills` and each + topic's `skills`, deduped by id with topic skills overriding model skills. Each entry's `prompt` is + ready to submit verbatim to `POST /api/v1/ai/jobs`. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiAgentActionsResponse | Any] + """ + + kwargs = _get_kwargs( + model_id=model_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> AiAgentActionsResponse | Any | None: + """Get model AI agent actions + + Returns the AI agent actions configured for this model — a unified list of sample queries and skills + suitable for surfacing as suggested prompts above an AI prompt input. Sample queries come from both + `model.sample_queries` and each topic's `sample_queries`; skills come from `model.skills` and each + topic's `skills`, deduped by id with topic skills overriding model skills. Each entry's `prompt` is + ready to submit verbatim to `POST /api/v1/ai/jobs`. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiAgentActionsResponse | Any + """ + + return sync_detailed( + model_id=model_id, + client=client, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[AiAgentActionsResponse | Any]: + """Get model AI agent actions + + Returns the AI agent actions configured for this model — a unified list of sample queries and skills + suitable for surfacing as suggested prompts above an AI prompt input. Sample queries come from both + `model.sample_queries` and each topic's `sample_queries`; skills come from `model.skills` and each + topic's `skills`, deduped by id with topic skills overriding model skills. Each entry's `prompt` is + ready to submit verbatim to `POST /api/v1/ai/jobs`. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiAgentActionsResponse | Any] + """ + + kwargs = _get_kwargs( + model_id=model_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> AiAgentActionsResponse | Any | None: + """Get model AI agent actions + + Returns the AI agent actions configured for this model — a unified list of sample queries and skills + suitable for surfacing as suggested prompts above an AI prompt input. Sample queries come from both + `model.sample_queries` and each topic's `sample_queries`; skills come from `model.skills` and each + topic's `skills`, deduped by id with topic skills overriding model skills. Each entry's `prompt` is + ready to submit verbatim to `POST /api/v1/ai/jobs`. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiAgentActionsResponse | Any + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_branch_dbt.py b/omni_python_sdk/api/models/models_branch_dbt.py new file mode 100644 index 0000000..6d5606c --- /dev/null +++ b/omni_python_sdk/api/models/models_branch_dbt.py @@ -0,0 +1,213 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_branch_dbt_body import ModelsBranchDbtBody +from ...models.success_response import SuccessResponse +from ...types import Response + + +def _get_kwargs( + model_id: UUID, + branch_name: str, + *, + body: ModelsBranchDbtBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/branch/{branch_name}/dbt".format( + model_id=quote(str(model_id), safe=""), + branch_name=quote(str(branch_name), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + branch_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsBranchDbtBody, +) -> Response[Any | SuccessResponse]: + """Set branch dbt environment + + Set the active dbt environment on a branch. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_name (str): Branch name Example: feature/new-metrics. + body (ModelsBranchDbtBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_name=branch_name, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + branch_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsBranchDbtBody, +) -> Any | SuccessResponse | None: + """Set branch dbt environment + + Set the active dbt environment on a branch. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_name (str): Branch name Example: feature/new-metrics. + body (ModelsBranchDbtBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + branch_name=branch_name, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + branch_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsBranchDbtBody, +) -> Response[Any | SuccessResponse]: + """Set branch dbt environment + + Set the active dbt environment on a branch. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_name (str): Branch name Example: feature/new-metrics. + body (ModelsBranchDbtBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_name=branch_name, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + branch_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsBranchDbtBody, +) -> Any | SuccessResponse | None: + """Set branch dbt environment + + Set the active dbt environment on a branch. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_name (str): Branch name Example: feature/new-metrics. + body (ModelsBranchDbtBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + branch_name=branch_name, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_cache_reset.py b/omni_python_sdk/api/models/models_cache_reset.py new file mode 100644 index 0000000..059cf2d --- /dev/null +++ b/omni_python_sdk/api/models/models_cache_reset.py @@ -0,0 +1,208 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_cache_reset_body import ModelsCacheResetBody +from ...models.models_cache_reset_response import ModelsCacheResetResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + policy_name: str, + *, + body: ModelsCacheResetBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/cache_reset/{policy_name}".format( + model_id=quote(str(model_id), safe=""), + policy_name=quote(str(policy_name), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsCacheResetResponse | None: + if response.status_code == 200: + response_200 = ModelsCacheResetResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsCacheResetResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + policy_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsCacheResetBody | Unset = UNSET, +) -> Response[Any | ModelsCacheResetResponse]: + """Reset cache for policy + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + policy_name (str): Cache policy name Example: daily_refresh. + body (ModelsCacheResetBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsCacheResetResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + policy_name=policy_name, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + policy_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsCacheResetBody | Unset = UNSET, +) -> Any | ModelsCacheResetResponse | None: + """Reset cache for policy + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + policy_name (str): Cache policy name Example: daily_refresh. + body (ModelsCacheResetBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsCacheResetResponse + """ + + return sync_detailed( + model_id=model_id, + policy_name=policy_name, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + policy_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsCacheResetBody | Unset = UNSET, +) -> Response[Any | ModelsCacheResetResponse]: + """Reset cache for policy + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + policy_name (str): Cache policy name Example: daily_refresh. + body (ModelsCacheResetBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsCacheResetResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + policy_name=policy_name, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + policy_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsCacheResetBody | Unset = UNSET, +) -> Any | ModelsCacheResetResponse | None: + """Reset cache for policy + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + policy_name (str): Cache policy name Example: daily_refresh. + body (ModelsCacheResetBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsCacheResetResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + policy_name=policy_name, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_commit.py b/omni_python_sdk/api/models/models_commit.py new file mode 100644 index 0000000..27c2803 --- /dev/null +++ b/omni_python_sdk/api/models/models_commit.py @@ -0,0 +1,209 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_commit_body import ModelsCommitBody +from ...models.models_commit_response import ModelsCommitResponse +from ...types import Response + + +def _get_kwargs( + model_id: UUID, + *, + body: ModelsCommitBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/git/commit".format( + model_id=quote(str(model_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsCommitResponse | None: + if response.status_code == 200: + response_200 = ModelsCommitResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsCommitResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsCommitBody, +) -> Response[Any | ModelsCommitResponse]: + """Commit branch to git + + Push the branch contents to git and create or update a pull request. The backend automatically + detects whether the git branch already exists: if not, it creates a new git branch and opens a PR; + if it does, it commits the latest model contents to the existing branch (updating the open PR). + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsCommitBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsCommitResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsCommitBody, +) -> Any | ModelsCommitResponse | None: + """Commit branch to git + + Push the branch contents to git and create or update a pull request. The backend automatically + detects whether the git branch already exists: if not, it creates a new git branch and opens a PR; + if it does, it commits the latest model contents to the existing branch (updating the open PR). + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsCommitBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsCommitResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsCommitBody, +) -> Response[Any | ModelsCommitResponse]: + """Commit branch to git + + Push the branch contents to git and create or update a pull request. The backend automatically + detects whether the git branch already exists: if not, it creates a new git branch and opens a PR; + if it does, it commits the latest model contents to the existing branch (updating the open PR). + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsCommitBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsCommitResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsCommitBody, +) -> Any | ModelsCommitResponse | None: + """Commit branch to git + + Push the branch contents to git and create or update a pull request. The backend automatically + detects whether the git branch already exists: if not, it creates a new git branch and opens a PR; + if it does, it commits the latest model contents to the existing branch (updating the open PR). + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsCommitBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsCommitResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_content_validator_get.py b/omni_python_sdk/api/models/models_content_validator_get.py new file mode 100644 index 0000000..8abdbdc --- /dev/null +++ b/omni_python_sdk/api/models/models_content_validator_get.py @@ -0,0 +1,375 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.content_filter_mode import ContentFilterMode +from ...models.models_content_validator_get_find_type import ( + ModelsContentValidatorGetFindType, +) +from ...models.models_content_validator_get_response import ModelsContentValidatorGetResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + branch_id: UUID | Unset = UNSET, + content_filter_mode: ContentFilterMode | Unset = UNSET, + creator_id: UUID | Unset = UNSET, + find: str | Unset = UNSET, + find_type: ModelsContentValidatorGetFindType | Unset = UNSET, + folder_paths: list[str] | Unset = UNSET, + include_personal_folders: bool | Unset = UNSET, + labels: str | Unset = UNSET, + user_id: str | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + json_content_filter_mode: str | Unset = UNSET + if not isinstance(content_filter_mode, Unset): + json_content_filter_mode = content_filter_mode + + params["content_filter_mode"] = json_content_filter_mode + + json_creator_id: str | Unset = UNSET + if not isinstance(creator_id, Unset): + json_creator_id = str(creator_id) + params["creator_id"] = json_creator_id + + params["find"] = find + + json_find_type: str | Unset = UNSET + if not isinstance(find_type, Unset): + json_find_type = find_type + + params["find_type"] = json_find_type + + json_folder_paths: list[str] | Unset = UNSET + if not isinstance(folder_paths, Unset): + json_folder_paths = folder_paths + + params["folder_paths"] = json_folder_paths + + params["include_personal_folders"] = include_personal_folders + + params["labels"] = labels + + params["userId"] = user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/content-validator".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsContentValidatorGetResponse | None: + if response.status_code == 200: + response_200 = ModelsContentValidatorGetResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsContentValidatorGetResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + content_filter_mode: ContentFilterMode | Unset = UNSET, + creator_id: UUID | Unset = UNSET, + find: str | Unset = UNSET, + find_type: ModelsContentValidatorGetFindType | Unset = UNSET, + folder_paths: list[str] | Unset = UNSET, + include_personal_folders: bool | Unset = UNSET, + labels: str | Unset = UNSET, + user_id: str | Unset = UNSET, +) -> Response[Any | ModelsContentValidatorGetResponse]: + """Validate content references + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Optional branch ID to validate against. Non-UUID values return + 400. + content_filter_mode (ContentFilterMode | Unset): Filter documents by issue status. ALL + (default) returns all documents with at least one query. WITH_ISSUES returns only + documents with at least one query issue, dashboard filter issue, or document error. + NO_ISSUES returns only documents with zero issues and no document errors. + creator_id (UUID | Unset): Filter to documents created by this user (user ID). Unknown IDs + return 400. + find (str | Unset): Optional value to find. Used with find_type to scope validation to a + single view, field, or topic. Requires find_type to be provided. + find_type (ModelsContentValidatorGetFindType | Unset): Optional type of find operation + (VIEW, FIELD, TOPIC). Requires find to be provided. FIELD values must be scoped by view + name (e.g. view_name.field_name). + folder_paths (list[str] | Unset): Prefix-match folder paths. "/Finance" matches + "/Finance/Reports". Documents with no folder are excluded unless "" is specified. + include_personal_folders (bool | Unset): Whether to include personal folders in validation + labels (str | Unset): Comma-separated label names. Documents matching any label are + included. Unknown labels return 400. + user_id (str | Unset): Optional user ID for scoping + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsContentValidatorGetResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + content_filter_mode=content_filter_mode, + creator_id=creator_id, + find=find, + find_type=find_type, + folder_paths=folder_paths, + include_personal_folders=include_personal_folders, + labels=labels, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + content_filter_mode: ContentFilterMode | Unset = UNSET, + creator_id: UUID | Unset = UNSET, + find: str | Unset = UNSET, + find_type: ModelsContentValidatorGetFindType | Unset = UNSET, + folder_paths: list[str] | Unset = UNSET, + include_personal_folders: bool | Unset = UNSET, + labels: str | Unset = UNSET, + user_id: str | Unset = UNSET, +) -> Any | ModelsContentValidatorGetResponse | None: + """Validate content references + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Optional branch ID to validate against. Non-UUID values return + 400. + content_filter_mode (ContentFilterMode | Unset): Filter documents by issue status. ALL + (default) returns all documents with at least one query. WITH_ISSUES returns only + documents with at least one query issue, dashboard filter issue, or document error. + NO_ISSUES returns only documents with zero issues and no document errors. + creator_id (UUID | Unset): Filter to documents created by this user (user ID). Unknown IDs + return 400. + find (str | Unset): Optional value to find. Used with find_type to scope validation to a + single view, field, or topic. Requires find_type to be provided. + find_type (ModelsContentValidatorGetFindType | Unset): Optional type of find operation + (VIEW, FIELD, TOPIC). Requires find to be provided. FIELD values must be scoped by view + name (e.g. view_name.field_name). + folder_paths (list[str] | Unset): Prefix-match folder paths. "/Finance" matches + "/Finance/Reports". Documents with no folder are excluded unless "" is specified. + include_personal_folders (bool | Unset): Whether to include personal folders in validation + labels (str | Unset): Comma-separated label names. Documents matching any label are + included. Unknown labels return 400. + user_id (str | Unset): Optional user ID for scoping + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsContentValidatorGetResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + content_filter_mode=content_filter_mode, + creator_id=creator_id, + find=find, + find_type=find_type, + folder_paths=folder_paths, + include_personal_folders=include_personal_folders, + labels=labels, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + content_filter_mode: ContentFilterMode | Unset = UNSET, + creator_id: UUID | Unset = UNSET, + find: str | Unset = UNSET, + find_type: ModelsContentValidatorGetFindType | Unset = UNSET, + folder_paths: list[str] | Unset = UNSET, + include_personal_folders: bool | Unset = UNSET, + labels: str | Unset = UNSET, + user_id: str | Unset = UNSET, +) -> Response[Any | ModelsContentValidatorGetResponse]: + """Validate content references + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Optional branch ID to validate against. Non-UUID values return + 400. + content_filter_mode (ContentFilterMode | Unset): Filter documents by issue status. ALL + (default) returns all documents with at least one query. WITH_ISSUES returns only + documents with at least one query issue, dashboard filter issue, or document error. + NO_ISSUES returns only documents with zero issues and no document errors. + creator_id (UUID | Unset): Filter to documents created by this user (user ID). Unknown IDs + return 400. + find (str | Unset): Optional value to find. Used with find_type to scope validation to a + single view, field, or topic. Requires find_type to be provided. + find_type (ModelsContentValidatorGetFindType | Unset): Optional type of find operation + (VIEW, FIELD, TOPIC). Requires find to be provided. FIELD values must be scoped by view + name (e.g. view_name.field_name). + folder_paths (list[str] | Unset): Prefix-match folder paths. "/Finance" matches + "/Finance/Reports". Documents with no folder are excluded unless "" is specified. + include_personal_folders (bool | Unset): Whether to include personal folders in validation + labels (str | Unset): Comma-separated label names. Documents matching any label are + included. Unknown labels return 400. + user_id (str | Unset): Optional user ID for scoping + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsContentValidatorGetResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + content_filter_mode=content_filter_mode, + creator_id=creator_id, + find=find, + find_type=find_type, + folder_paths=folder_paths, + include_personal_folders=include_personal_folders, + labels=labels, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + content_filter_mode: ContentFilterMode | Unset = UNSET, + creator_id: UUID | Unset = UNSET, + find: str | Unset = UNSET, + find_type: ModelsContentValidatorGetFindType | Unset = UNSET, + folder_paths: list[str] | Unset = UNSET, + include_personal_folders: bool | Unset = UNSET, + labels: str | Unset = UNSET, + user_id: str | Unset = UNSET, +) -> Any | ModelsContentValidatorGetResponse | None: + """Validate content references + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Optional branch ID to validate against. Non-UUID values return + 400. + content_filter_mode (ContentFilterMode | Unset): Filter documents by issue status. ALL + (default) returns all documents with at least one query. WITH_ISSUES returns only + documents with at least one query issue, dashboard filter issue, or document error. + NO_ISSUES returns only documents with zero issues and no document errors. + creator_id (UUID | Unset): Filter to documents created by this user (user ID). Unknown IDs + return 400. + find (str | Unset): Optional value to find. Used with find_type to scope validation to a + single view, field, or topic. Requires find_type to be provided. + find_type (ModelsContentValidatorGetFindType | Unset): Optional type of find operation + (VIEW, FIELD, TOPIC). Requires find to be provided. FIELD values must be scoped by view + name (e.g. view_name.field_name). + folder_paths (list[str] | Unset): Prefix-match folder paths. "/Finance" matches + "/Finance/Reports". Documents with no folder are excluded unless "" is specified. + include_personal_folders (bool | Unset): Whether to include personal folders in validation + labels (str | Unset): Comma-separated label names. Documents matching any label are + included. Unknown labels return 400. + user_id (str | Unset): Optional user ID for scoping + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsContentValidatorGetResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + content_filter_mode=content_filter_mode, + creator_id=creator_id, + find=find, + find_type=find_type, + folder_paths=folder_paths, + include_personal_folders=include_personal_folders, + labels=labels, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_content_validator_replace.py b/omni_python_sdk/api/models/models_content_validator_replace.py new file mode 100644 index 0000000..cf2dc73 --- /dev/null +++ b/omni_python_sdk/api/models/models_content_validator_replace.py @@ -0,0 +1,217 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_content_validator_replace_body import ModelsContentValidatorReplaceBody +from ...models.models_content_validator_replace_response import ModelsContentValidatorReplaceResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + body: ModelsContentValidatorReplaceBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/content-validator".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsContentValidatorReplaceResponse | None: + if response.status_code == 200: + response_200 = ModelsContentValidatorReplaceResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsContentValidatorReplaceResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsContentValidatorReplaceBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | ModelsContentValidatorReplaceResponse]: + """Replace content references + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (ModelsContentValidatorReplaceBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsContentValidatorReplaceResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsContentValidatorReplaceBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | ModelsContentValidatorReplaceResponse | None: + """Replace content references + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (ModelsContentValidatorReplaceBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsContentValidatorReplaceResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + body=body, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsContentValidatorReplaceBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | ModelsContentValidatorReplaceResponse]: + """Replace content references + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (ModelsContentValidatorReplaceBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsContentValidatorReplaceResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsContentValidatorReplaceBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | ModelsContentValidatorReplaceResponse | None: + """Replace content references + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (ModelsContentValidatorReplaceBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsContentValidatorReplaceResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + body=body, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_create.py b/omni_python_sdk/api/models/models_create.py new file mode 100644 index 0000000..d7ea55b --- /dev/null +++ b/omni_python_sdk/api/models/models_create.py @@ -0,0 +1,185 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.create_model_schema_base import CreateModelSchemaBase +from ...models.models_create_models_create_response import ModelsCreateModelsCreateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: CreateModelSchemaBase | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models", + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsCreateModelsCreateResponse | None: + if response.status_code == 200: + response_200 = ModelsCreateModelsCreateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsCreateModelsCreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: CreateModelSchemaBase | Unset = UNSET, +) -> Response[Any | ModelsCreateModelsCreateResponse]: + """Create model + + Create a new model. Supports creating schema, shared, branch, and shared_extension models. + + Args: + body (CreateModelSchemaBase | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsCreateModelsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: CreateModelSchemaBase | Unset = UNSET, +) -> Any | ModelsCreateModelsCreateResponse | None: + """Create model + + Create a new model. Supports creating schema, shared, branch, and shared_extension models. + + Args: + body (CreateModelSchemaBase | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsCreateModelsCreateResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: CreateModelSchemaBase | Unset = UNSET, +) -> Response[Any | ModelsCreateModelsCreateResponse]: + """Create model + + Create a new model. Supports creating schema, shared, branch, and shared_extension models. + + Args: + body (CreateModelSchemaBase | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsCreateModelsCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: CreateModelSchemaBase | Unset = UNSET, +) -> Any | ModelsCreateModelsCreateResponse | None: + """Create model + + Create a new model. Supports creating schema, shared, branch, and shared_extension models. + + Args: + body (CreateModelSchemaBase | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsCreateModelsCreateResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_create_field.py b/omni_python_sdk/api/models/models_create_field.py new file mode 100644 index 0000000..63d42ef --- /dev/null +++ b/omni_python_sdk/api/models/models_create_field.py @@ -0,0 +1,192 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_create_field_body import ModelsCreateFieldBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + body: ModelsCreateFieldBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/field".format( + model_id=quote(str(model_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 201: + response_201 = SuccessResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsCreateFieldBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Create field + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsCreateFieldBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsCreateFieldBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Create field + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsCreateFieldBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsCreateFieldBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Create field + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsCreateFieldBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsCreateFieldBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Create field + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsCreateFieldBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_dbt_exposures.py b/omni_python_sdk/api/models/models_dbt_exposures.py new file mode 100644 index 0000000..9391aec --- /dev/null +++ b/omni_python_sdk/api/models/models_dbt_exposures.py @@ -0,0 +1,303 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_dbt_exposures_response import ModelsDbtExposuresResponse +from ...models.models_dbt_exposures_sort_direction import ( + ModelsDbtExposuresSortDirection, +) +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ModelsDbtExposuresSortDirection | Unset = "desc", + sort_field: str | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["pageSize"] = page_size + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + params["sortField"] = sort_field + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/dbt-exposures".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsDbtExposuresResponse | None: + if response.status_code == 200: + response_200 = ModelsDbtExposuresResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsDbtExposuresResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ModelsDbtExposuresSortDirection | Unset = "desc", + sort_field: str | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | ModelsDbtExposuresResponse]: + """Get dbt exposures + + Returns the dbt exposures for a model, computed on-demand by analyzing which dbt models are + referenced by dashboards that use this model. Returns exactly one record per dashboard. The exposure + field is null when a dashboard does not reference any dbt models. Exposure names (exposure.name) may + contain duplicates when multiple dashboards produce the same name; use deduplication_name for a + guaranteed-unique value, or use it as a fallback when names collide. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (ModelsDbtExposuresSortDirection | Unset): Sort direction for results + Default: 'desc'. Example: desc. + sort_field (str | Unset): Field to sort results by + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsDbtExposuresResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + branch_id=branch_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ModelsDbtExposuresSortDirection | Unset = "desc", + sort_field: str | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Any | ModelsDbtExposuresResponse | None: + """Get dbt exposures + + Returns the dbt exposures for a model, computed on-demand by analyzing which dbt models are + referenced by dashboards that use this model. Returns exactly one record per dashboard. The exposure + field is null when a dashboard does not reference any dbt models. Exposure names (exposure.name) may + contain duplicates when multiple dashboards produce the same name; use deduplication_name for a + guaranteed-unique value, or use it as a fallback when names collide. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (ModelsDbtExposuresSortDirection | Unset): Sort direction for results + Default: 'desc'. Example: desc. + sort_field (str | Unset): Field to sort results by + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsDbtExposuresResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + branch_id=branch_id, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ModelsDbtExposuresSortDirection | Unset = "desc", + sort_field: str | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | ModelsDbtExposuresResponse]: + """Get dbt exposures + + Returns the dbt exposures for a model, computed on-demand by analyzing which dbt models are + referenced by dashboards that use this model. Returns exactly one record per dashboard. The exposure + field is null when a dashboard does not reference any dbt models. Exposure names (exposure.name) may + contain duplicates when multiple dashboards produce the same name; use deduplication_name for a + guaranteed-unique value, or use it as a fallback when names collide. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (ModelsDbtExposuresSortDirection | Unset): Sort direction for results + Default: 'desc'. Example: desc. + sort_field (str | Unset): Field to sort results by + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsDbtExposuresResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + branch_id=branch_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: ModelsDbtExposuresSortDirection | Unset = "desc", + sort_field: str | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Any | ModelsDbtExposuresResponse | None: + """Get dbt exposures + + Returns the dbt exposures for a model, computed on-demand by analyzing which dbt models are + referenced by dashboards that use this model. Returns exactly one record per dashboard. The exposure + field is null when a dashboard does not reference any dbt models. Exposure names (exposure.name) may + contain duplicates when multiple dashboards produce the same name; use deduplication_name for a + guaranteed-unique value, or use it as a fallback when names collide. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (ModelsDbtExposuresSortDirection | Unset): Sort direction for results + Default: 'desc'. Example: desc. + sort_field (str | Unset): Field to sort results by + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsDbtExposuresResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + branch_id=branch_id, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_dbt_sync.py b/omni_python_sdk/api/models/models_dbt_sync.py new file mode 100644 index 0000000..42efa7c --- /dev/null +++ b/omni_python_sdk/api/models/models_dbt_sync.py @@ -0,0 +1,230 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.job_created_response import JobCreatedResponse +from ...types import UNSET, Response + + +def _get_kwargs( + model_id: UUID, + *, + branch_id: UUID, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/dbt-sync".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | JobCreatedResponse | None: + if response.status_code == 200: + response_200 = JobCreatedResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if response.status_code == 422: + response_422 = cast(Any, None) + return response_422 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | JobCreatedResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID, +) -> Response[Any | JobCreatedResponse]: + r"""Trigger a dbt metadata sync for a branch + + Trigger a dbt metadata sync (\"dbt quick sync\") for a branch. Recompiles the branch's dbt manifest + and merges the regenerated dbt extension model, without a full database schema scan. The branch (via + branch_id) supplies the dbt environment and dbt git branch. Runs as a background job. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID): ID of the branch to sync dbt metadata for. The branch supplies the dbt + environment and dbt git branch to compile against (set via POST + /api/v1/models/{modelId}/branch/{branchName}/dbt). Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | JobCreatedResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID, +) -> Any | JobCreatedResponse | None: + r"""Trigger a dbt metadata sync for a branch + + Trigger a dbt metadata sync (\"dbt quick sync\") for a branch. Recompiles the branch's dbt manifest + and merges the regenerated dbt extension model, without a full database schema scan. The branch (via + branch_id) supplies the dbt environment and dbt git branch. Runs as a background job. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID): ID of the branch to sync dbt metadata for. The branch supplies the dbt + environment and dbt git branch to compile against (set via POST + /api/v1/models/{modelId}/branch/{branchName}/dbt). Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | JobCreatedResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID, +) -> Response[Any | JobCreatedResponse]: + r"""Trigger a dbt metadata sync for a branch + + Trigger a dbt metadata sync (\"dbt quick sync\") for a branch. Recompiles the branch's dbt manifest + and merges the regenerated dbt extension model, without a full database schema scan. The branch (via + branch_id) supplies the dbt environment and dbt git branch. Runs as a background job. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID): ID of the branch to sync dbt metadata for. The branch supplies the dbt + environment and dbt git branch to compile against (set via POST + /api/v1/models/{modelId}/branch/{branchName}/dbt). Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | JobCreatedResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID, +) -> Any | JobCreatedResponse | None: + r"""Trigger a dbt metadata sync for a branch + + Trigger a dbt metadata sync (\"dbt quick sync\") for a branch. Recompiles the branch's dbt manifest + and merges the regenerated dbt extension model, without a full database schema scan. The branch (via + branch_id) supplies the dbt environment and dbt git branch. Runs as a background job. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID): ID of the branch to sync dbt metadata for. The branch supplies the dbt + environment and dbt git branch to compile against (set via POST + /api/v1/models/{modelId}/branch/{branchName}/dbt). Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | JobCreatedResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_delete_branch.py b/omni_python_sdk/api/models/models_delete_branch.py new file mode 100644 index 0000000..2dcaaec --- /dev/null +++ b/omni_python_sdk/api/models/models_delete_branch.py @@ -0,0 +1,180 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.success_response import SuccessResponse +from ...types import Response + + +def _get_kwargs( + model_id: UUID, + branch_name: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/models/{model_id}/branch/{branch_name}".format( + model_id=quote(str(model_id), safe=""), + branch_name=quote(str(branch_name), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + branch_name: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Delete branch + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_name (str): Branch name Example: feature/new-metrics. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_name=branch_name, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + branch_name: str, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Delete branch + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_name (str): Branch name Example: feature/new-metrics. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + branch_name=branch_name, + client=client, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + branch_name: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Delete branch + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_name (str): Branch name Example: feature/new-metrics. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_name=branch_name, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + branch_name: str, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Delete branch + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_name (str): Branch name Example: feature/new-metrics. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + branch_name=branch_name, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_delete_field.py b/omni_python_sdk/api/models/models_delete_field.py new file mode 100644 index 0000000..1b614ce --- /dev/null +++ b/omni_python_sdk/api/models/models_delete_field.py @@ -0,0 +1,233 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + view_name: str, + field_name: str, + *, + branch_id: UUID | Unset = UNSET, + topic_context: str | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + params["topic_context"] = topic_context + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/models/{model_id}/view/{view_name}/field/{field_name}".format( + model_id=quote(str(model_id), safe=""), + view_name=quote(str(view_name), safe=""), + field_name=quote(str(field_name), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + view_name: str, + field_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + topic_context: str | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Delete field + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + field_name (str): Field name Example: total_amount. + branch_id (UUID | Unset): Branch ID + topic_context (str | Unset): Topic context for the field + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + view_name=view_name, + field_name=field_name, + branch_id=branch_id, + topic_context=topic_context, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + view_name: str, + field_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + topic_context: str | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Delete field + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + field_name (str): Field name Example: total_amount. + branch_id (UUID | Unset): Branch ID + topic_context (str | Unset): Topic context for the field + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + view_name=view_name, + field_name=field_name, + client=client, + branch_id=branch_id, + topic_context=topic_context, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + view_name: str, + field_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + topic_context: str | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Delete field + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + field_name (str): Field name Example: total_amount. + branch_id (UUID | Unset): Branch ID + topic_context (str | Unset): Topic context for the field + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + view_name=view_name, + field_name=field_name, + branch_id=branch_id, + topic_context=topic_context, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + view_name: str, + field_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + topic_context: str | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Delete field + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + field_name (str): Field name Example: total_amount. + branch_id (UUID | Unset): Branch ID + topic_context (str | Unset): Topic context for the field + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + view_name=view_name, + field_name=field_name, + client=client, + branch_id=branch_id, + topic_context=topic_context, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_delete_topic.py b/omni_python_sdk/api/models/models_delete_topic.py new file mode 100644 index 0000000..b67b56f --- /dev/null +++ b/omni_python_sdk/api/models/models_delete_topic.py @@ -0,0 +1,240 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_delete_topic_mode import ModelsDeleteTopicMode +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + topic_name: str, + *, + branch_id: UUID | Unset = UNSET, + mode: ModelsDeleteTopicMode | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + json_mode: str | Unset = UNSET + if not isinstance(mode, Unset): + json_mode = mode + + params["mode"] = json_mode + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/models/{model_id}/topic/{topic_name}".format( + model_id=quote(str(model_id), safe=""), + topic_name=quote(str(topic_name), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + topic_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + mode: ModelsDeleteTopicMode | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Delete topic + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + topic_name (str): Topic name Example: sales_analytics. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + mode (ModelsDeleteTopicMode | Unset): Controls delete behavior to match IDE editing modes. + COMBINED (default) adds the topic to deletedTopics if it exists in the parent model + (prevents reappearing). MERGED behaves the same as COMBINED. EXTENSION hard-deletes the + topic from the extension layer. Example: COMBINED. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + topic_name=topic_name, + branch_id=branch_id, + mode=mode, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + topic_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + mode: ModelsDeleteTopicMode | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Delete topic + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + topic_name (str): Topic name Example: sales_analytics. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + mode (ModelsDeleteTopicMode | Unset): Controls delete behavior to match IDE editing modes. + COMBINED (default) adds the topic to deletedTopics if it exists in the parent model + (prevents reappearing). MERGED behaves the same as COMBINED. EXTENSION hard-deletes the + topic from the extension layer. Example: COMBINED. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + topic_name=topic_name, + client=client, + branch_id=branch_id, + mode=mode, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + topic_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + mode: ModelsDeleteTopicMode | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Delete topic + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + topic_name (str): Topic name Example: sales_analytics. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + mode (ModelsDeleteTopicMode | Unset): Controls delete behavior to match IDE editing modes. + COMBINED (default) adds the topic to deletedTopics if it exists in the parent model + (prevents reappearing). MERGED behaves the same as COMBINED. EXTENSION hard-deletes the + topic from the extension layer. Example: COMBINED. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + topic_name=topic_name, + branch_id=branch_id, + mode=mode, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + topic_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + mode: ModelsDeleteTopicMode | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Delete topic + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + topic_name (str): Topic name Example: sales_analytics. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + mode (ModelsDeleteTopicMode | Unset): Controls delete behavior to match IDE editing modes. + COMBINED (default) adds the topic to deletedTopics if it exists in the parent model + (prevents reappearing). MERGED behaves the same as COMBINED. EXTENSION hard-deletes the + topic from the extension layer. Example: COMBINED. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + topic_name=topic_name, + client=client, + branch_id=branch_id, + mode=mode, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_delete_view.py b/omni_python_sdk/api/models/models_delete_view.py new file mode 100644 index 0000000..3f7119e --- /dev/null +++ b/omni_python_sdk/api/models/models_delete_view.py @@ -0,0 +1,240 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_delete_view_mode import ModelsDeleteViewMode +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + view_name: str, + *, + branch_id: UUID | Unset = UNSET, + mode: ModelsDeleteViewMode | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + json_mode: str | Unset = UNSET + if not isinstance(mode, Unset): + json_mode = mode + + params["mode"] = json_mode + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/models/{model_id}/view/{view_name}".format( + model_id=quote(str(model_id), safe=""), + view_name=quote(str(view_name), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + view_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + mode: ModelsDeleteViewMode | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Delete view + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + mode (ModelsDeleteViewMode | Unset): Controls delete behavior to match IDE editing modes. + COMBINED (default) marks the view as ignored if it exists in the parent model, otherwise + hard-deletes. MERGED marks the view as shallowIgnored (hidden only from the immediate + parent). EXTENSION hard-deletes the view from the extension layer. Example: COMBINED. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + view_name=view_name, + branch_id=branch_id, + mode=mode, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + view_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + mode: ModelsDeleteViewMode | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Delete view + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + mode (ModelsDeleteViewMode | Unset): Controls delete behavior to match IDE editing modes. + COMBINED (default) marks the view as ignored if it exists in the parent model, otherwise + hard-deletes. MERGED marks the view as shallowIgnored (hidden only from the immediate + parent). EXTENSION hard-deletes the view from the extension layer. Example: COMBINED. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + view_name=view_name, + client=client, + branch_id=branch_id, + mode=mode, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + view_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + mode: ModelsDeleteViewMode | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Delete view + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + mode (ModelsDeleteViewMode | Unset): Controls delete behavior to match IDE editing modes. + COMBINED (default) marks the view as ignored if it exists in the parent model, otherwise + hard-deletes. MERGED marks the view as shallowIgnored (hidden only from the immediate + parent). EXTENSION hard-deletes the view from the extension layer. Example: COMBINED. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + view_name=view_name, + branch_id=branch_id, + mode=mode, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + view_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + mode: ModelsDeleteViewMode | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Delete view + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + mode (ModelsDeleteViewMode | Unset): Controls delete behavior to match IDE editing modes. + COMBINED (default) marks the view as ignored if it exists in the parent model, otherwise + hard-deletes. MERGED marks the view as shallowIgnored (hidden only from the immediate + parent). EXTENSION hard-deletes the view from the extension layer. Example: COMBINED. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + view_name=view_name, + client=client, + branch_id=branch_id, + mode=mode, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_get_schemas.py b/omni_python_sdk/api/models/models_get_schemas.py new file mode 100644 index 0000000..0624552 --- /dev/null +++ b/omni_python_sdk/api/models/models_get_schemas.py @@ -0,0 +1,196 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_get_schemas_response import ModelsGetSchemasResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + branch_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/schemas".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsGetSchemasResponse | None: + if response.status_code == 200: + response_200 = ModelsGetSchemasResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsGetSchemasResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | ModelsGetSchemasResponse]: + """List available schemas for a model + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGetSchemasResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Any | ModelsGetSchemasResponse | None: + """List available schemas for a model + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGetSchemasResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | ModelsGetSchemasResponse]: + """List available schemas for a model + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGetSchemasResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Any | ModelsGetSchemasResponse | None: + """List available schemas for a model + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGetSchemasResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_get_topic.py b/omni_python_sdk/api/models/models_get_topic.py new file mode 100644 index 0000000..3bbd912 --- /dev/null +++ b/omni_python_sdk/api/models/models_get_topic.py @@ -0,0 +1,210 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_get_topic_response import ModelsGetTopicResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + topic_name: str, + *, + branch_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/topic/{topic_name}".format( + model_id=quote(str(model_id), safe=""), + topic_name=quote(str(topic_name), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsGetTopicResponse | None: + if response.status_code == 200: + response_200 = ModelsGetTopicResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsGetTopicResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + topic_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | ModelsGetTopicResponse]: + """Get topic + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + topic_name (str): Topic name Example: sales_analytics. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGetTopicResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + topic_name=topic_name, + branch_id=branch_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + topic_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Any | ModelsGetTopicResponse | None: + """Get topic + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + topic_name (str): Topic name Example: sales_analytics. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGetTopicResponse + """ + + return sync_detailed( + model_id=model_id, + topic_name=topic_name, + client=client, + branch_id=branch_id, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + topic_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | ModelsGetTopicResponse]: + """Get topic + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + topic_name (str): Topic name Example: sales_analytics. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGetTopicResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + topic_name=topic_name, + branch_id=branch_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + topic_name: str, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Any | ModelsGetTopicResponse | None: + """Get topic + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + topic_name (str): Topic name Example: sales_analytics. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGetTopicResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + topic_name=topic_name, + client=client, + branch_id=branch_id, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_get_views.py b/omni_python_sdk/api/models/models_get_views.py new file mode 100644 index 0000000..d96dc6c --- /dev/null +++ b/omni_python_sdk/api/models/models_get_views.py @@ -0,0 +1,196 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_get_view_response import ModelsGetViewResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + branch_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/view".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsGetViewResponse | None: + if response.status_code == 200: + response_200 = ModelsGetViewResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsGetViewResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | ModelsGetViewResponse]: + """Get model views + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGetViewResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Any | ModelsGetViewResponse | None: + """Get model views + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGetViewResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | ModelsGetViewResponse]: + """Get model views + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGetViewResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Any | ModelsGetViewResponse | None: + """Get model views + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGetViewResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_git_create.py b/omni_python_sdk/api/models/models_git_create.py new file mode 100644 index 0000000..9be4ed4 --- /dev/null +++ b/omni_python_sdk/api/models/models_git_create.py @@ -0,0 +1,198 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_git_create_body import ModelsGitCreateBody +from ...models.models_git_create_response import ModelsGitCreateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + body: ModelsGitCreateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/git".format( + model_id=quote(str(model_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsGitCreateResponse | None: + if response.status_code == 201: + response_201 = ModelsGitCreateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsGitCreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsGitCreateBody | Unset = UNSET, +) -> Response[Any | ModelsGitCreateResponse]: + """Create git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsGitCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGitCreateResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsGitCreateBody | Unset = UNSET, +) -> Any | ModelsGitCreateResponse | None: + """Create git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsGitCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGitCreateResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsGitCreateBody | Unset = UNSET, +) -> Response[Any | ModelsGitCreateResponse]: + """Create git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsGitCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGitCreateResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsGitCreateBody | Unset = UNSET, +) -> Any | ModelsGitCreateResponse | None: + """Create git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsGitCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGitCreateResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_git_delete.py b/omni_python_sdk/api/models/models_git_delete.py new file mode 100644 index 0000000..4c6a61b --- /dev/null +++ b/omni_python_sdk/api/models/models_git_delete.py @@ -0,0 +1,168 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_git_delete_response import ModelsGitDeleteResponse +from ...types import Response + + +def _get_kwargs( + model_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/models/{model_id}/git".format( + model_id=quote(str(model_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsGitDeleteResponse | None: + if response.status_code == 200: + response_200 = ModelsGitDeleteResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsGitDeleteResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ModelsGitDeleteResponse]: + """Delete git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGitDeleteResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ModelsGitDeleteResponse | None: + """Delete git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGitDeleteResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ModelsGitDeleteResponse]: + """Delete git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGitDeleteResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ModelsGitDeleteResponse | None: + """Delete git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGitDeleteResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_git_get.py b/omni_python_sdk/api/models/models_git_get.py new file mode 100644 index 0000000..e9562aa --- /dev/null +++ b/omni_python_sdk/api/models/models_git_get.py @@ -0,0 +1,193 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_git_get_response import ModelsGitGetResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + include: str | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["include"] = include + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/git".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsGitGetResponse | None: + if response.status_code == 200: + response_200 = ModelsGitGetResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsGitGetResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + include: str | Unset = UNSET, +) -> Response[Any | ModelsGitGetResponse]: + """Get git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + include (str | Unset): Comma-separated list of optional fields to include. Supported: + "webhookSecret" Example: webhookSecret. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGitGetResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + include=include, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + include: str | Unset = UNSET, +) -> Any | ModelsGitGetResponse | None: + """Get git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + include (str | Unset): Comma-separated list of optional fields to include. Supported: + "webhookSecret" Example: webhookSecret. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGitGetResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + include=include, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + include: str | Unset = UNSET, +) -> Response[Any | ModelsGitGetResponse]: + """Get git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + include (str | Unset): Comma-separated list of optional fields to include. Supported: + "webhookSecret" Example: webhookSecret. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGitGetResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + include=include, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + include: str | Unset = UNSET, +) -> Any | ModelsGitGetResponse | None: + """Get git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + include (str | Unset): Comma-separated list of optional fields to include. Supported: + "webhookSecret" Example: webhookSecret. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGitGetResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + include=include, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_git_sync.py b/omni_python_sdk/api/models/models_git_sync.py new file mode 100644 index 0000000..dcc0f62 --- /dev/null +++ b/omni_python_sdk/api/models/models_git_sync.py @@ -0,0 +1,190 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_git_sync_body import ModelsGitSyncBody +from ...models.models_git_sync_response import ModelsGitSyncResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + body: ModelsGitSyncBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/git/sync".format( + model_id=quote(str(model_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsGitSyncResponse | None: + if response.status_code == 200: + response_200 = ModelsGitSyncResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsGitSyncResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsGitSyncBody | Unset = UNSET, +) -> Response[Any | ModelsGitSyncResponse]: + """Sync model with git + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsGitSyncBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGitSyncResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsGitSyncBody | Unset = UNSET, +) -> Any | ModelsGitSyncResponse | None: + """Sync model with git + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsGitSyncBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGitSyncResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsGitSyncBody | Unset = UNSET, +) -> Response[Any | ModelsGitSyncResponse]: + """Sync model with git + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsGitSyncBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGitSyncResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsGitSyncBody | Unset = UNSET, +) -> Any | ModelsGitSyncResponse | None: + """Sync model with git + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsGitSyncBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGitSyncResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_git_update.py b/omni_python_sdk/api/models/models_git_update.py new file mode 100644 index 0000000..c4e1a7f --- /dev/null +++ b/omni_python_sdk/api/models/models_git_update.py @@ -0,0 +1,194 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_git_update_body import ModelsGitUpdateBody +from ...models.models_git_update_response import ModelsGitUpdateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + body: ModelsGitUpdateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/models/{model_id}/git".format( + model_id=quote(str(model_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsGitUpdateResponse | None: + if response.status_code == 200: + response_200 = ModelsGitUpdateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsGitUpdateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsGitUpdateBody | Unset = UNSET, +) -> Response[Any | ModelsGitUpdateResponse]: + """Update git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsGitUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGitUpdateResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsGitUpdateBody | Unset = UNSET, +) -> Any | ModelsGitUpdateResponse | None: + """Update git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsGitUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGitUpdateResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsGitUpdateBody | Unset = UNSET, +) -> Response[Any | ModelsGitUpdateResponse]: + """Update git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsGitUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsGitUpdateResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsGitUpdateBody | Unset = UNSET, +) -> Any | ModelsGitUpdateResponse | None: + """Update git configuration + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsGitUpdateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsGitUpdateResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_list.py b/omni_python_sdk/api/models/models_list.py new file mode 100644 index 0000000..ffb8dd3 --- /dev/null +++ b/omni_python_sdk/api/models/models_list.py @@ -0,0 +1,352 @@ +from http import HTTPStatus +from typing import Any, cast +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_list_include_deleted import ModelsListIncludeDeleted +from ...models.models_list_model_kind import ModelsListModelKind +from ...models.models_list_response import ModelsListResponse +from ...models.models_list_sort_direction import ModelsListSortDirection +from ...models.models_list_sort_field import ModelsListSortField +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + base_model_id: UUID | Unset = UNSET, + connection_id: UUID | Unset = UNSET, + cursor: str | Unset = UNSET, + include: str | Unset = UNSET, + include_deleted: ModelsListIncludeDeleted | Unset = UNSET, + model_id: UUID | Unset = UNSET, + model_kind: ModelsListModelKind | Unset = UNSET, + name: str | Unset = UNSET, + page_size: int | Unset = UNSET, + sort_direction: ModelsListSortDirection | Unset = UNSET, + sort_field: ModelsListSortField | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_base_model_id: str | Unset = UNSET + if not isinstance(base_model_id, Unset): + json_base_model_id = str(base_model_id) + params["baseModelId"] = json_base_model_id + + json_connection_id: str | Unset = UNSET + if not isinstance(connection_id, Unset): + json_connection_id = str(connection_id) + params["connectionId"] = json_connection_id + + params["cursor"] = cursor + + params["include"] = include + + json_include_deleted: str | Unset = UNSET + if not isinstance(include_deleted, Unset): + json_include_deleted = include_deleted + + params["includeDeleted"] = json_include_deleted + + json_model_id: str | Unset = UNSET + if not isinstance(model_id, Unset): + json_model_id = str(model_id) + params["modelId"] = json_model_id + + json_model_kind: str | Unset = UNSET + if not isinstance(model_kind, Unset): + json_model_kind = model_kind + + params["modelKind"] = json_model_kind + + params["name"] = name + + params["pageSize"] = page_size + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + json_sort_field: str | Unset = UNSET + if not isinstance(sort_field, Unset): + json_sort_field = sort_field + + params["sortField"] = json_sort_field + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsListResponse | None: + if response.status_code == 200: + response_200 = ModelsListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + base_model_id: UUID | Unset = UNSET, + connection_id: UUID | Unset = UNSET, + cursor: str | Unset = UNSET, + include: str | Unset = UNSET, + include_deleted: ModelsListIncludeDeleted | Unset = UNSET, + model_id: UUID | Unset = UNSET, + model_kind: ModelsListModelKind | Unset = UNSET, + name: str | Unset = UNSET, + page_size: int | Unset = UNSET, + sort_direction: ModelsListSortDirection | Unset = UNSET, + sort_field: ModelsListSortField | Unset = UNSET, +) -> Response[Any | ModelsListResponse]: + """List models + + Args: + base_model_id (UUID | Unset): Filter by base model ID + connection_id (UUID | Unset): Filter by connection ID + cursor (str | Unset): Cursor for pagination + include (str | Unset): Comma-separated list of fields to include (e.g., activeBranches) + Example: activeBranches. + include_deleted (ModelsListIncludeDeleted | Unset): Include deleted models + model_id (UUID | Unset): Filter by specific model ID + model_kind (ModelsListModelKind | Unset): Filter by model kind + name (str | Unset): Filter by model name + page_size (int | Unset): Number of results per page Example: 20. + sort_direction (ModelsListSortDirection | Unset): Sort direction + sort_field (ModelsListSortField | Unset): Field to sort by + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsListResponse] + """ + + kwargs = _get_kwargs( + base_model_id=base_model_id, + connection_id=connection_id, + cursor=cursor, + include=include, + include_deleted=include_deleted, + model_id=model_id, + model_kind=model_kind, + name=name, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + base_model_id: UUID | Unset = UNSET, + connection_id: UUID | Unset = UNSET, + cursor: str | Unset = UNSET, + include: str | Unset = UNSET, + include_deleted: ModelsListIncludeDeleted | Unset = UNSET, + model_id: UUID | Unset = UNSET, + model_kind: ModelsListModelKind | Unset = UNSET, + name: str | Unset = UNSET, + page_size: int | Unset = UNSET, + sort_direction: ModelsListSortDirection | Unset = UNSET, + sort_field: ModelsListSortField | Unset = UNSET, +) -> Any | ModelsListResponse | None: + """List models + + Args: + base_model_id (UUID | Unset): Filter by base model ID + connection_id (UUID | Unset): Filter by connection ID + cursor (str | Unset): Cursor for pagination + include (str | Unset): Comma-separated list of fields to include (e.g., activeBranches) + Example: activeBranches. + include_deleted (ModelsListIncludeDeleted | Unset): Include deleted models + model_id (UUID | Unset): Filter by specific model ID + model_kind (ModelsListModelKind | Unset): Filter by model kind + name (str | Unset): Filter by model name + page_size (int | Unset): Number of results per page Example: 20. + sort_direction (ModelsListSortDirection | Unset): Sort direction + sort_field (ModelsListSortField | Unset): Field to sort by + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsListResponse + """ + + return sync_detailed( + client=client, + base_model_id=base_model_id, + connection_id=connection_id, + cursor=cursor, + include=include, + include_deleted=include_deleted, + model_id=model_id, + model_kind=model_kind, + name=name, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + base_model_id: UUID | Unset = UNSET, + connection_id: UUID | Unset = UNSET, + cursor: str | Unset = UNSET, + include: str | Unset = UNSET, + include_deleted: ModelsListIncludeDeleted | Unset = UNSET, + model_id: UUID | Unset = UNSET, + model_kind: ModelsListModelKind | Unset = UNSET, + name: str | Unset = UNSET, + page_size: int | Unset = UNSET, + sort_direction: ModelsListSortDirection | Unset = UNSET, + sort_field: ModelsListSortField | Unset = UNSET, +) -> Response[Any | ModelsListResponse]: + """List models + + Args: + base_model_id (UUID | Unset): Filter by base model ID + connection_id (UUID | Unset): Filter by connection ID + cursor (str | Unset): Cursor for pagination + include (str | Unset): Comma-separated list of fields to include (e.g., activeBranches) + Example: activeBranches. + include_deleted (ModelsListIncludeDeleted | Unset): Include deleted models + model_id (UUID | Unset): Filter by specific model ID + model_kind (ModelsListModelKind | Unset): Filter by model kind + name (str | Unset): Filter by model name + page_size (int | Unset): Number of results per page Example: 20. + sort_direction (ModelsListSortDirection | Unset): Sort direction + sort_field (ModelsListSortField | Unset): Field to sort by + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsListResponse] + """ + + kwargs = _get_kwargs( + base_model_id=base_model_id, + connection_id=connection_id, + cursor=cursor, + include=include, + include_deleted=include_deleted, + model_id=model_id, + model_kind=model_kind, + name=name, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + base_model_id: UUID | Unset = UNSET, + connection_id: UUID | Unset = UNSET, + cursor: str | Unset = UNSET, + include: str | Unset = UNSET, + include_deleted: ModelsListIncludeDeleted | Unset = UNSET, + model_id: UUID | Unset = UNSET, + model_kind: ModelsListModelKind | Unset = UNSET, + name: str | Unset = UNSET, + page_size: int | Unset = UNSET, + sort_direction: ModelsListSortDirection | Unset = UNSET, + sort_field: ModelsListSortField | Unset = UNSET, +) -> Any | ModelsListResponse | None: + """List models + + Args: + base_model_id (UUID | Unset): Filter by base model ID + connection_id (UUID | Unset): Filter by connection ID + cursor (str | Unset): Cursor for pagination + include (str | Unset): Comma-separated list of fields to include (e.g., activeBranches) + Example: activeBranches. + include_deleted (ModelsListIncludeDeleted | Unset): Include deleted models + model_id (UUID | Unset): Filter by specific model ID + model_kind (ModelsListModelKind | Unset): Filter by model kind + name (str | Unset): Filter by model name + page_size (int | Unset): Number of results per page Example: 20. + sort_direction (ModelsListSortDirection | Unset): Sort direction + sort_field (ModelsListSortField | Unset): Field to sort by + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsListResponse + """ + + return ( + await asyncio_detailed( + client=client, + base_model_id=base_model_id, + connection_id=connection_id, + cursor=cursor, + include=include, + include_deleted=include_deleted, + model_id=model_id, + model_kind=model_kind, + name=name, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_list_topics.py b/omni_python_sdk/api/models/models_list_topics.py new file mode 100644 index 0000000..28e0baa --- /dev/null +++ b/omni_python_sdk/api/models/models_list_topics.py @@ -0,0 +1,196 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_list_topics_response import ModelsListTopicsResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + branch_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/topic".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsListTopicsResponse | None: + if response.status_code == 200: + response_200 = ModelsListTopicsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsListTopicsResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | ModelsListTopicsResponse]: + """List topics + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsListTopicsResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Any | ModelsListTopicsResponse | None: + """List topics + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsListTopicsResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | ModelsListTopicsResponse]: + """List topics + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsListTopicsResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, +) -> Any | ModelsListTopicsResponse | None: + """List topics + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsListTopicsResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_merge_branch.py b/omni_python_sdk/api/models/models_merge_branch.py new file mode 100644 index 0000000..5c790dd --- /dev/null +++ b/omni_python_sdk/api/models/models_merge_branch.py @@ -0,0 +1,208 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_merge_branch_body import ModelsMergeBranchBody +from ...models.models_merge_branch_response import ModelsMergeBranchResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + branch_name: str, + *, + body: ModelsMergeBranchBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/branch/{branch_name}/merge".format( + model_id=quote(str(model_id), safe=""), + branch_name=quote(str(branch_name), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsMergeBranchResponse | None: + if response.status_code == 200: + response_200 = ModelsMergeBranchResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsMergeBranchResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + branch_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsMergeBranchBody | Unset = UNSET, +) -> Response[Any | ModelsMergeBranchResponse]: + """Merge branch + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_name (str): Branch name Example: feature/new-metrics. + body (ModelsMergeBranchBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsMergeBranchResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_name=branch_name, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + branch_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsMergeBranchBody | Unset = UNSET, +) -> Any | ModelsMergeBranchResponse | None: + """Merge branch + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_name (str): Branch name Example: feature/new-metrics. + body (ModelsMergeBranchBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsMergeBranchResponse + """ + + return sync_detailed( + model_id=model_id, + branch_name=branch_name, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + branch_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsMergeBranchBody | Unset = UNSET, +) -> Response[Any | ModelsMergeBranchResponse]: + """Merge branch + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_name (str): Branch name Example: feature/new-metrics. + body (ModelsMergeBranchBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsMergeBranchResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_name=branch_name, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + branch_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsMergeBranchBody | Unset = UNSET, +) -> Any | ModelsMergeBranchResponse | None: + """Merge branch + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_name (str): Branch name Example: feature/new-metrics. + body (ModelsMergeBranchBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsMergeBranchResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + branch_name=branch_name, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_migrate.py b/omni_python_sdk/api/models/models_migrate.py new file mode 100644 index 0000000..2ccaefd --- /dev/null +++ b/omni_python_sdk/api/models/models_migrate.py @@ -0,0 +1,192 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_migrate_body import ModelsMigrateBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + body: ModelsMigrateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/migrate".format( + model_id=quote(str(model_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsMigrateBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Migrate model + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsMigrateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsMigrateBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Migrate model + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsMigrateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsMigrateBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Migrate model + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsMigrateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsMigrateBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Migrate model + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsMigrateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_refresh.py b/omni_python_sdk/api/models/models_refresh.py new file mode 100644 index 0000000..1815751 --- /dev/null +++ b/omni_python_sdk/api/models/models_refresh.py @@ -0,0 +1,282 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_refresh_hard_refresh import ModelsRefreshHardRefresh +from ...models.models_refresh_response import ModelsRefreshResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + branch_id: UUID | Unset = UNSET, + hard_refresh: ModelsRefreshHardRefresh | Unset = UNSET, + schemas: str | Unset = UNSET, + tables: str | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + json_hard_refresh: str | Unset = UNSET + if not isinstance(hard_refresh, Unset): + json_hard_refresh = hard_refresh + + params["hard_refresh"] = json_hard_refresh + + params["schemas"] = schemas + + params["tables"] = tables + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/refresh".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsRefreshResponse | None: + if response.status_code == 200: + response_200 = ModelsRefreshResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsRefreshResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + hard_refresh: ModelsRefreshHardRefresh | Unset = UNSET, + schemas: str | Unset = UNSET, + tables: str | Unset = UNSET, +) -> Response[Any | ModelsRefreshResponse]: + """Refresh model schema + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID for branch-based schema refresh. Required when branch- + based schema refresh is enabled for the connection. Must not be provided when branch-based + schema refresh is not enabled. Example: 123e4567-e89b-12d3-a456-426614174001. + hard_refresh (ModelsRefreshHardRefresh | Unset): When true (the default), performs a hard + refresh that fully discards and rebuilds the schema model. When false, performs a soft + refresh that merges newly generated views with the existing model. Must be set to false + when `schemas` or `tables` filters are provided. Example: false. + schemas (str | Unset): Optional comma-separated list of schemas to refresh selectively. + Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires + `hard_refresh=false`. Example: public,analytics. + tables (str | Unset): Optional comma-separated list of tables to refresh selectively. Only + the listed tables are reloaded; the rest of the schema model is preserved. Requires + `hard_refresh=false`. Example: public.orders,public.customers. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsRefreshResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + hard_refresh=hard_refresh, + schemas=schemas, + tables=tables, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + hard_refresh: ModelsRefreshHardRefresh | Unset = UNSET, + schemas: str | Unset = UNSET, + tables: str | Unset = UNSET, +) -> Any | ModelsRefreshResponse | None: + """Refresh model schema + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID for branch-based schema refresh. Required when branch- + based schema refresh is enabled for the connection. Must not be provided when branch-based + schema refresh is not enabled. Example: 123e4567-e89b-12d3-a456-426614174001. + hard_refresh (ModelsRefreshHardRefresh | Unset): When true (the default), performs a hard + refresh that fully discards and rebuilds the schema model. When false, performs a soft + refresh that merges newly generated views with the existing model. Must be set to false + when `schemas` or `tables` filters are provided. Example: false. + schemas (str | Unset): Optional comma-separated list of schemas to refresh selectively. + Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires + `hard_refresh=false`. Example: public,analytics. + tables (str | Unset): Optional comma-separated list of tables to refresh selectively. Only + the listed tables are reloaded; the rest of the schema model is preserved. Requires + `hard_refresh=false`. Example: public.orders,public.customers. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsRefreshResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + hard_refresh=hard_refresh, + schemas=schemas, + tables=tables, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + hard_refresh: ModelsRefreshHardRefresh | Unset = UNSET, + schemas: str | Unset = UNSET, + tables: str | Unset = UNSET, +) -> Response[Any | ModelsRefreshResponse]: + """Refresh model schema + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID for branch-based schema refresh. Required when branch- + based schema refresh is enabled for the connection. Must not be provided when branch-based + schema refresh is not enabled. Example: 123e4567-e89b-12d3-a456-426614174001. + hard_refresh (ModelsRefreshHardRefresh | Unset): When true (the default), performs a hard + refresh that fully discards and rebuilds the schema model. When false, performs a soft + refresh that merges newly generated views with the existing model. Must be set to false + when `schemas` or `tables` filters are provided. Example: false. + schemas (str | Unset): Optional comma-separated list of schemas to refresh selectively. + Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires + `hard_refresh=false`. Example: public,analytics. + tables (str | Unset): Optional comma-separated list of tables to refresh selectively. Only + the listed tables are reloaded; the rest of the schema model is preserved. Requires + `hard_refresh=false`. Example: public.orders,public.customers. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsRefreshResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + hard_refresh=hard_refresh, + schemas=schemas, + tables=tables, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + hard_refresh: ModelsRefreshHardRefresh | Unset = UNSET, + schemas: str | Unset = UNSET, + tables: str | Unset = UNSET, +) -> Any | ModelsRefreshResponse | None: + """Refresh model schema + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID for branch-based schema refresh. Required when branch- + based schema refresh is enabled for the connection. Must not be provided when branch-based + schema refresh is not enabled. Example: 123e4567-e89b-12d3-a456-426614174001. + hard_refresh (ModelsRefreshHardRefresh | Unset): When true (the default), performs a hard + refresh that fully discards and rebuilds the schema model. When false, performs a soft + refresh that merges newly generated views with the existing model. Must be set to false + when `schemas` or `tables` filters are provided. Example: false. + schemas (str | Unset): Optional comma-separated list of schemas to refresh selectively. + Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires + `hard_refresh=false`. Example: public,analytics. + tables (str | Unset): Optional comma-separated list of tables to refresh selectively. Only + the listed tables are reloaded; the rest of the schema model is preserved. Requires + `hard_refresh=false`. Example: public.orders,public.customers. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsRefreshResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + hard_refresh=hard_refresh, + schemas=schemas, + tables=tables, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_update.py b/omni_python_sdk/api/models/models_update.py new file mode 100644 index 0000000..0cae84f --- /dev/null +++ b/omni_python_sdk/api/models/models_update.py @@ -0,0 +1,201 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_update_body import ModelsUpdateBody +from ...models.models_update_response import ModelsUpdateResponse +from ...types import Response + + +def _get_kwargs( + model_id: UUID, + *, + body: ModelsUpdateBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/models/{model_id}".format( + model_id=quote(str(model_id), safe=""), + ), + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsUpdateResponse | None: + if response.status_code == 200: + response_200 = ModelsUpdateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsUpdateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateBody, +) -> Response[Any | ModelsUpdateResponse]: + """Update model + + Update metadata for an existing model. Currently supports renaming the model via the `name` field. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsUpdateResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateBody, +) -> Any | ModelsUpdateResponse | None: + """Update model + + Update metadata for an existing model. Currently supports renaming the model via the `name` field. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsUpdateResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateBody, +) -> Response[Any | ModelsUpdateResponse]: + """Update model + + Update metadata for an existing model. Currently supports renaming the model via the `name` field. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsUpdateResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateBody, +) -> Any | ModelsUpdateResponse | None: + """Update model + + Update metadata for an existing model. Currently supports renaming the model via the `name` field. + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsUpdateResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_update_field.py b/omni_python_sdk/api/models/models_update_field.py new file mode 100644 index 0000000..11a079f --- /dev/null +++ b/omni_python_sdk/api/models/models_update_field.py @@ -0,0 +1,247 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_update_field_body import ModelsUpdateFieldBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + view_name: str, + field_name: str, + *, + body: ModelsUpdateFieldBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/models/{model_id}/view/{view_name}/field/{field_name}".format( + model_id=quote(str(model_id), safe=""), + view_name=quote(str(view_name), safe=""), + field_name=quote(str(field_name), safe=""), + ), + "params": params, + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + view_name: str, + field_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateFieldBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Update field + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + field_name (str): Field name Example: total_amount. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + body (ModelsUpdateFieldBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + view_name=view_name, + field_name=field_name, + body=body, + branch_id=branch_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + view_name: str, + field_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateFieldBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Update field + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + field_name (str): Field name Example: total_amount. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + body (ModelsUpdateFieldBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + view_name=view_name, + field_name=field_name, + client=client, + body=body, + branch_id=branch_id, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + view_name: str, + field_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateFieldBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Update field + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + field_name (str): Field name Example: total_amount. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + body (ModelsUpdateFieldBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + view_name=view_name, + field_name=field_name, + body=body, + branch_id=branch_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + view_name: str, + field_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateFieldBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Update field + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + field_name (str): Field name Example: total_amount. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + body (ModelsUpdateFieldBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + view_name=view_name, + field_name=field_name, + client=client, + body=body, + branch_id=branch_id, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_update_topic.py b/omni_python_sdk/api/models/models_update_topic.py new file mode 100644 index 0000000..0056be8 --- /dev/null +++ b/omni_python_sdk/api/models/models_update_topic.py @@ -0,0 +1,233 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_update_topic_body import ModelsUpdateTopicBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + topic_name: str, + *, + body: ModelsUpdateTopicBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/models/{model_id}/topic/{topic_name}".format( + model_id=quote(str(model_id), safe=""), + topic_name=quote(str(topic_name), safe=""), + ), + "params": params, + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + topic_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateTopicBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Update topic + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + topic_name (str): Topic name Example: sales_analytics. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + body (ModelsUpdateTopicBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + topic_name=topic_name, + body=body, + branch_id=branch_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + topic_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateTopicBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Update topic + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + topic_name (str): Topic name Example: sales_analytics. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + body (ModelsUpdateTopicBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + topic_name=topic_name, + client=client, + body=body, + branch_id=branch_id, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + topic_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateTopicBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Update topic + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + topic_name (str): Topic name Example: sales_analytics. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + body (ModelsUpdateTopicBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + topic_name=topic_name, + body=body, + branch_id=branch_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + topic_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateTopicBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Update topic + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + topic_name (str): Topic name Example: sales_analytics. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + body (ModelsUpdateTopicBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + topic_name=topic_name, + client=client, + body=body, + branch_id=branch_id, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_update_view.py b/omni_python_sdk/api/models/models_update_view.py new file mode 100644 index 0000000..b1a8986 --- /dev/null +++ b/omni_python_sdk/api/models/models_update_view.py @@ -0,0 +1,233 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_update_view_body import ModelsUpdateViewBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + view_name: str, + *, + body: ModelsUpdateViewBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branch_id"] = json_branch_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/models/{model_id}/view/{view_name}".format( + model_id=quote(str(model_id), safe=""), + view_name=quote(str(view_name), safe=""), + ), + "params": params, + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + view_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateViewBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Update view + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + body (ModelsUpdateViewBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + view_name=view_name, + body=body, + branch_id=branch_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + view_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateViewBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Update view + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + body (ModelsUpdateViewBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + model_id=model_id, + view_name=view_name, + client=client, + body=body, + branch_id=branch_id, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + view_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateViewBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Update view + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + body (ModelsUpdateViewBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + view_name=view_name, + body=body, + branch_id=branch_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + view_name: str, + *, + client: AuthenticatedClient | Client, + body: ModelsUpdateViewBody | Unset = UNSET, + branch_id: UUID | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Update view + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + view_name (str): View name Example: orders. + branch_id (UUID | Unset): Branch ID to use for branch-aware operations Example: + 123e4567-e89b-12d3-a456-426614174001. + body (ModelsUpdateViewBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + view_name=view_name, + client=client, + body=body, + branch_id=branch_id, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_validate.py b/omni_python_sdk/api/models/models_validate.py new file mode 100644 index 0000000..176ca9a --- /dev/null +++ b/omni_python_sdk/api/models/models_validate.py @@ -0,0 +1,207 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_validate_response import ModelsValidateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + branch_id: UUID | Unset = UNSET, + limit: int | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branchId"] = json_branch_id + + params["limit"] = limit + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/validate".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelsValidateResponse | None: + if response.status_code == 200: + response_200 = ModelsValidateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelsValidateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + limit: int | Unset = UNSET, +) -> Response[Any | ModelsValidateResponse]: + """Validate model + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to validate + limit (int | Unset): Maximum number of validation issues to return + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsValidateResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + limit=limit, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + limit: int | Unset = UNSET, +) -> Any | ModelsValidateResponse | None: + """Validate model + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to validate + limit (int | Unset): Maximum number of validation issues to return + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsValidateResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + limit=limit, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + limit: int | Unset = UNSET, +) -> Response[Any | ModelsValidateResponse]: + """Validate model + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to validate + limit (int | Unset): Maximum number of validation issues to return + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelsValidateResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + limit=limit, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + limit: int | Unset = UNSET, +) -> Any | ModelsValidateResponse | None: + """Validate model + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID to validate + limit (int | Unset): Maximum number of validation issues to return + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelsValidateResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + limit=limit, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_yaml_create.py b/omni_python_sdk/api/models/models_yaml_create.py new file mode 100644 index 0000000..79d9d48 --- /dev/null +++ b/omni_python_sdk/api/models/models_yaml_create.py @@ -0,0 +1,198 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.model_yaml_create_request_body import ModelYamlCreateRequestBody +from ...models.model_yaml_response import ModelYamlResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + body: ModelYamlCreateRequestBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/yaml".format( + model_id=quote(str(model_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelYamlResponse | None: + if response.status_code == 200: + response_200 = ModelYamlResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelYamlResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelYamlCreateRequestBody | Unset = UNSET, +) -> Response[Any | ModelYamlResponse]: + """Update model YAML + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelYamlCreateRequestBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelYamlResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelYamlCreateRequestBody | Unset = UNSET, +) -> Any | ModelYamlResponse | None: + """Update model YAML + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelYamlCreateRequestBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelYamlResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelYamlCreateRequestBody | Unset = UNSET, +) -> Response[Any | ModelYamlResponse]: + """Update model YAML + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelYamlCreateRequestBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelYamlResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + body: ModelYamlCreateRequestBody | Unset = UNSET, +) -> Any | ModelYamlResponse | None: + """Update model YAML + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + body (ModelYamlCreateRequestBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelYamlResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_yaml_delete.py b/omni_python_sdk/api/models/models_yaml_delete.py new file mode 100644 index 0000000..e1e15c1 --- /dev/null +++ b/omni_python_sdk/api/models/models_yaml_delete.py @@ -0,0 +1,163 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.models_yaml_delete_mode import ModelsYamlDeleteMode +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + branch_id: UUID | Unset = UNSET, + file_name: str, + mode: ModelsYamlDeleteMode | Unset = "combined", + commit_message: str | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branchId"] = json_branch_id + + json_file_name: str + json_file_name = file_name + params["fileName"] = json_file_name + + json_mode: str | Unset = UNSET + if not isinstance(mode, Unset): + json_mode = mode + + params["mode"] = json_mode + + params["commitMessage"] = commit_message + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/models/{model_id}/yaml".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None: + if response.status_code == 200: + return None + + if response.status_code == 400: + return None + + if response.status_code == 401: + return None + + if response.status_code == 403: + return None + + if response.status_code == 404: + return None + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + file_name: str, + mode: ModelsYamlDeleteMode | Unset = "combined", + commit_message: str | Unset = UNSET, +) -> Response[Any]: + """Delete model YAML file + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID for branch-aware operations + file_name (str): File name to delete (must end with '.topic' or '.view') + mode (ModelsYamlDeleteMode | Unset): IDE mode for YAML operations Default: 'combined'. + commit_message (str | Unset): Commit message for git sync + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + file_name=file_name, + mode=mode, + commit_message=commit_message, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + file_name: str, + mode: ModelsYamlDeleteMode | Unset = "combined", + commit_message: str | Unset = UNSET, +) -> Response[Any]: + """Delete model YAML file + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID for branch-aware operations + file_name (str): File name to delete (must end with '.topic' or '.view') + mode (ModelsYamlDeleteMode | Unset): IDE mode for YAML operations Default: 'combined'. + commit_message (str | Unset): Commit message for git sync + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + file_name=file_name, + mode=mode, + commit_message=commit_message, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/omni_python_sdk/api/models/models_yaml_get.py b/omni_python_sdk/api/models/models_yaml_get.py new file mode 100644 index 0000000..6eb907f --- /dev/null +++ b/omni_python_sdk/api/models/models_yaml_get.py @@ -0,0 +1,298 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.model_yaml_response import ModelYamlResponse +from ...models.models_yaml_get_mode import ModelsYamlGetMode +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + model_id: UUID, + *, + branch_id: UUID | Unset = UNSET, + file_name: str | Unset = UNSET, + mode: ModelsYamlGetMode | Unset = "combined", + fully_resolved: bool | str | Unset = "False", + include_checksums: bool | None | Unset = False, + include_schemas: str | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_branch_id: str | Unset = UNSET + if not isinstance(branch_id, Unset): + json_branch_id = str(branch_id) + params["branchId"] = json_branch_id + + params["fileName"] = file_name + + json_mode: str | Unset = UNSET + if not isinstance(mode, Unset): + json_mode = mode + + params["mode"] = json_mode + + json_fully_resolved: bool | str | Unset + if isinstance(fully_resolved, Unset): + json_fully_resolved = UNSET + else: + json_fully_resolved = fully_resolved + params["fullyResolved"] = json_fully_resolved + + json_include_checksums: bool | None | Unset + if isinstance(include_checksums, Unset): + json_include_checksums = UNSET + else: + json_include_checksums = include_checksums + params["includeChecksums"] = json_include_checksums + + params["includeSchemas"] = include_schemas + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/yaml".format( + model_id=quote(str(model_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ModelYamlResponse | None: + if response.status_code == 200: + response_200 = ModelYamlResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ModelYamlResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + file_name: str | Unset = UNSET, + mode: ModelsYamlGetMode | Unset = "combined", + fully_resolved: bool | str | Unset = "False", + include_checksums: bool | None | Unset = False, + include_schemas: str | Unset = UNSET, +) -> Response[Any | ModelYamlResponse]: + """Get model YAML + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID for branch-aware operations + file_name (str | Unset): File name to operate on + mode (ModelsYamlGetMode | Unset): IDE mode for YAML operations Default: 'combined'. + fully_resolved (bool | str | Unset): Resolve the model extends chain so the returned YAML + reflects what runs at query time. Only valid with mode=combined. Default: 'False'. + include_checksums (bool | None | Unset): Include checksums in response Default: False. + include_schemas (str | Unset): A single schema name (optionally catalog-scoped, e.g. + 'warehouse.reporting') to additionally load into the response. Use this to include view + YAML from a schema that isn't active in the model (inactive or offloaded). Only views from + this schema will be returned (views with no schema are always included). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelYamlResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + file_name=file_name, + mode=mode, + fully_resolved=fully_resolved, + include_checksums=include_checksums, + include_schemas=include_schemas, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + file_name: str | Unset = UNSET, + mode: ModelsYamlGetMode | Unset = "combined", + fully_resolved: bool | str | Unset = "False", + include_checksums: bool | None | Unset = False, + include_schemas: str | Unset = UNSET, +) -> Any | ModelYamlResponse | None: + """Get model YAML + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID for branch-aware operations + file_name (str | Unset): File name to operate on + mode (ModelsYamlGetMode | Unset): IDE mode for YAML operations Default: 'combined'. + fully_resolved (bool | str | Unset): Resolve the model extends chain so the returned YAML + reflects what runs at query time. Only valid with mode=combined. Default: 'False'. + include_checksums (bool | None | Unset): Include checksums in response Default: False. + include_schemas (str | Unset): A single schema name (optionally catalog-scoped, e.g. + 'warehouse.reporting') to additionally load into the response. Use this to include view + YAML from a schema that isn't active in the model (inactive or offloaded). Only views from + this schema will be returned (views with no schema are always included). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelYamlResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + file_name=file_name, + mode=mode, + fully_resolved=fully_resolved, + include_checksums=include_checksums, + include_schemas=include_schemas, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + file_name: str | Unset = UNSET, + mode: ModelsYamlGetMode | Unset = "combined", + fully_resolved: bool | str | Unset = "False", + include_checksums: bool | None | Unset = False, + include_schemas: str | Unset = UNSET, +) -> Response[Any | ModelYamlResponse]: + """Get model YAML + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID for branch-aware operations + file_name (str | Unset): File name to operate on + mode (ModelsYamlGetMode | Unset): IDE mode for YAML operations Default: 'combined'. + fully_resolved (bool | str | Unset): Resolve the model extends chain so the returned YAML + reflects what runs at query time. Only valid with mode=combined. Default: 'False'. + include_checksums (bool | None | Unset): Include checksums in response Default: False. + include_schemas (str | Unset): A single schema name (optionally catalog-scoped, e.g. + 'warehouse.reporting') to additionally load into the response. Use this to include view + YAML from a schema that isn't active in the model (inactive or offloaded). Only views from + this schema will be returned (views with no schema are always included). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ModelYamlResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + branch_id=branch_id, + file_name=file_name, + mode=mode, + fully_resolved=fully_resolved, + include_checksums=include_checksums, + include_schemas=include_schemas, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, + branch_id: UUID | Unset = UNSET, + file_name: str | Unset = UNSET, + mode: ModelsYamlGetMode | Unset = "combined", + fully_resolved: bool | str | Unset = "False", + include_checksums: bool | None | Unset = False, + include_schemas: str | Unset = UNSET, +) -> Any | ModelYamlResponse | None: + """Get model YAML + + Args: + model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. + branch_id (UUID | Unset): Branch ID for branch-aware operations + file_name (str | Unset): File name to operate on + mode (ModelsYamlGetMode | Unset): IDE mode for YAML operations Default: 'combined'. + fully_resolved (bool | str | Unset): Resolve the model extends chain so the returned YAML + reflects what runs at query time. Only valid with mode=combined. Default: 'False'. + include_checksums (bool | None | Unset): Include checksums in response Default: False. + include_schemas (str | Unset): A single schema name (optionally catalog-scoped, e.g. + 'warehouse.reporting') to additionally load into the response. Use this to include view + YAML from a schema that isn't active in the model (inactive or offloaded). Only views from + this schema will be returned (views with no schema are always included). + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ModelYamlResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + branch_id=branch_id, + file_name=file_name, + mode=mode, + fully_resolved=fully_resolved, + include_checksums=include_checksums, + include_schemas=include_schemas, + ) + ).parsed diff --git a/omni_python_sdk/api/query/__init__.py b/omni_python_sdk/api/query/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/query/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/query/query_run.py b/omni_python_sdk/api/query/query_run.py new file mode 100644 index 0000000..3156e03 --- /dev/null +++ b/omni_python_sdk/api/query/query_run.py @@ -0,0 +1,211 @@ +from http import HTTPStatus +from typing import Any, cast +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.query_run_body import QueryRunBody +from ...models.query_run_response import QueryRunResponse +from ...models.query_timeout_response import QueryTimeoutResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: QueryRunBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/query/run", + "params": params, + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | QueryRunResponse | QueryTimeoutResponse | None: + if response.status_code == 200: + response_200 = QueryRunResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 408: + response_408 = QueryTimeoutResponse.from_dict(response.json()) + + return response_408 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | QueryRunResponse | QueryTimeoutResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: QueryRunBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | QueryRunResponse | QueryTimeoutResponse]: + """Execute a semantic query + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (QueryRunBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | QueryRunResponse | QueryTimeoutResponse] + """ + + kwargs = _get_kwargs( + body=body, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: QueryRunBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | QueryRunResponse | QueryTimeoutResponse | None: + """Execute a semantic query + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (QueryRunBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | QueryRunResponse | QueryTimeoutResponse + """ + + return sync_detailed( + client=client, + body=body, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: QueryRunBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | QueryRunResponse | QueryTimeoutResponse]: + """Execute a semantic query + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (QueryRunBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | QueryRunResponse | QueryTimeoutResponse] + """ + + kwargs = _get_kwargs( + body=body, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: QueryRunBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | QueryRunResponse | QueryTimeoutResponse | None: + """Execute a semantic query + + Args: + user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) + body (QueryRunBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | QueryRunResponse | QueryTimeoutResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/query/query_wait.py b/omni_python_sdk/api/query/query_wait.py new file mode 100644 index 0000000..41c0ef3 --- /dev/null +++ b/omni_python_sdk/api/query/query_wait.py @@ -0,0 +1,180 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.query_wait_response import QueryWaitResponse +from ...types import UNSET, Response + + +def _get_kwargs( + *, + job_ids: str, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["jobIds"] = job_ids + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/query/wait", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | QueryWaitResponse | None: + if response.status_code == 200: + response_200 = QueryWaitResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | QueryWaitResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + job_ids: str, +) -> Response[Any | QueryWaitResponse]: + """Wait for query jobs to complete + + Args: + job_ids (str): Comma-separated list of job IDs to wait for. Obtained from the query/run + response. Example: job_abc123,job_def456. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | QueryWaitResponse] + """ + + kwargs = _get_kwargs( + job_ids=job_ids, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + job_ids: str, +) -> Any | QueryWaitResponse | None: + """Wait for query jobs to complete + + Args: + job_ids (str): Comma-separated list of job IDs to wait for. Obtained from the query/run + response. Example: job_abc123,job_def456. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | QueryWaitResponse + """ + + return sync_detailed( + client=client, + job_ids=job_ids, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + job_ids: str, +) -> Response[Any | QueryWaitResponse]: + """Wait for query jobs to complete + + Args: + job_ids (str): Comma-separated list of job IDs to wait for. Obtained from the query/run + response. Example: job_abc123,job_def456. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | QueryWaitResponse] + """ + + kwargs = _get_kwargs( + job_ids=job_ids, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + job_ids: str, +) -> Any | QueryWaitResponse | None: + """Wait for query jobs to complete + + Args: + job_ids (str): Comma-separated list of job IDs to wait for. Obtained from the query/run + response. Example: job_abc123,job_def456. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | QueryWaitResponse + """ + + return ( + await asyncio_detailed( + client=client, + job_ids=job_ids, + ) + ).parsed diff --git a/omni_python_sdk/api/schedules/__init__.py b/omni_python_sdk/api/schedules/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/schedules/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/schedules/schedules_add_recipients.py b/omni_python_sdk/api/schedules/schedules_add_recipients.py new file mode 100644 index 0000000..33510d4 --- /dev/null +++ b/omni_python_sdk/api/schedules/schedules_add_recipients.py @@ -0,0 +1,198 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.schedules_add_recipients_body import SchedulesAddRecipientsBody +from ...models.schedules_add_recipients_response import SchedulesAddRecipientsResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + schedule_id: UUID, + *, + body: SchedulesAddRecipientsBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/schedules/{schedule_id}/add-recipients".format( + schedule_id=quote(str(schedule_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | SchedulesAddRecipientsResponse | None: + if response.status_code == 200: + response_200 = SchedulesAddRecipientsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SchedulesAddRecipientsResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: SchedulesAddRecipientsBody | Unset = UNSET, +) -> Response[Any | SchedulesAddRecipientsResponse]: + """Add schedule recipients + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + body (SchedulesAddRecipientsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SchedulesAddRecipientsResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: SchedulesAddRecipientsBody | Unset = UNSET, +) -> Any | SchedulesAddRecipientsResponse | None: + """Add schedule recipients + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + body (SchedulesAddRecipientsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SchedulesAddRecipientsResponse + """ + + return sync_detailed( + schedule_id=schedule_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: SchedulesAddRecipientsBody | Unset = UNSET, +) -> Response[Any | SchedulesAddRecipientsResponse]: + """Add schedule recipients + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + body (SchedulesAddRecipientsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SchedulesAddRecipientsResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: SchedulesAddRecipientsBody | Unset = UNSET, +) -> Any | SchedulesAddRecipientsResponse | None: + """Add schedule recipients + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + body (SchedulesAddRecipientsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SchedulesAddRecipientsResponse + """ + + return ( + await asyncio_detailed( + schedule_id=schedule_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/schedules/schedules_create.py b/omni_python_sdk/api/schedules/schedules_create.py new file mode 100644 index 0000000..f24ab11 --- /dev/null +++ b/omni_python_sdk/api/schedules/schedules_create.py @@ -0,0 +1,229 @@ +from http import HTTPStatus +from typing import Any, cast +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.schedules_create_schedules_create_body import SchedulesCreateSchedulesCreateBody +from ...models.schedules_create_schedules_create_response import SchedulesCreateSchedulesCreateResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: SchedulesCreateSchedulesCreateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/schedules", + "params": params, + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | SchedulesCreateSchedulesCreateResponse | None: + if response.status_code == 200: + response_200 = SchedulesCreateSchedulesCreateResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SchedulesCreateSchedulesCreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: SchedulesCreateSchedulesCreateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | SchedulesCreateSchedulesCreateResponse]: + """Create schedule + + Create a new scheduled delivery for a dashboard. Required fields vary by destinationType (email, + webhook, sftp, slack). For org API keys, use the userId query parameter to create the schedule on + behalf of a specific user. + + Args: + user_id (UUID | Unset): Membership ID of the user who should own the schedule (org API + keys only). If not provided, the schedule is owned by the API key owner. User-scoped API + keys cannot use this parameter. Example: 987fcdeb-51a2-43d7-9b56-254415f67890. + body (SchedulesCreateSchedulesCreateBody | Unset): Request body for creating a scheduled + task. Required fields vary by destinationType. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SchedulesCreateSchedulesCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: SchedulesCreateSchedulesCreateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | SchedulesCreateSchedulesCreateResponse | None: + """Create schedule + + Create a new scheduled delivery for a dashboard. Required fields vary by destinationType (email, + webhook, sftp, slack). For org API keys, use the userId query parameter to create the schedule on + behalf of a specific user. + + Args: + user_id (UUID | Unset): Membership ID of the user who should own the schedule (org API + keys only). If not provided, the schedule is owned by the API key owner. User-scoped API + keys cannot use this parameter. Example: 987fcdeb-51a2-43d7-9b56-254415f67890. + body (SchedulesCreateSchedulesCreateBody | Unset): Request body for creating a scheduled + task. Required fields vary by destinationType. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SchedulesCreateSchedulesCreateResponse + """ + + return sync_detailed( + client=client, + body=body, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: SchedulesCreateSchedulesCreateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Response[Any | SchedulesCreateSchedulesCreateResponse]: + """Create schedule + + Create a new scheduled delivery for a dashboard. Required fields vary by destinationType (email, + webhook, sftp, slack). For org API keys, use the userId query parameter to create the schedule on + behalf of a specific user. + + Args: + user_id (UUID | Unset): Membership ID of the user who should own the schedule (org API + keys only). If not provided, the schedule is owned by the API key owner. User-scoped API + keys cannot use this parameter. Example: 987fcdeb-51a2-43d7-9b56-254415f67890. + body (SchedulesCreateSchedulesCreateBody | Unset): Request body for creating a scheduled + task. Required fields vary by destinationType. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SchedulesCreateSchedulesCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: SchedulesCreateSchedulesCreateBody | Unset = UNSET, + user_id: UUID | Unset = UNSET, +) -> Any | SchedulesCreateSchedulesCreateResponse | None: + """Create schedule + + Create a new scheduled delivery for a dashboard. Required fields vary by destinationType (email, + webhook, sftp, slack). For org API keys, use the userId query parameter to create the schedule on + behalf of a specific user. + + Args: + user_id (UUID | Unset): Membership ID of the user who should own the schedule (org API + keys only). If not provided, the schedule is owned by the API key owner. User-scoped API + keys cannot use this parameter. Example: 987fcdeb-51a2-43d7-9b56-254415f67890. + body (SchedulesCreateSchedulesCreateBody | Unset): Request body for creating a scheduled + task. Required fields vary by destinationType. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SchedulesCreateSchedulesCreateResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/schedules/schedules_delete.py b/omni_python_sdk/api/schedules/schedules_delete.py new file mode 100644 index 0000000..973bbbe --- /dev/null +++ b/omni_python_sdk/api/schedules/schedules_delete.py @@ -0,0 +1,170 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.success_response import SuccessResponse +from ...types import Response + + +def _get_kwargs( + schedule_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/schedules/{schedule_id}".format( + schedule_id=quote(str(schedule_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Delete schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Delete schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + schedule_id=schedule_id, + client=client, + ).parsed + + +async def asyncio_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Delete schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Delete schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + schedule_id=schedule_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/schedules/schedules_get.py b/omni_python_sdk/api/schedules/schedules_get.py new file mode 100644 index 0000000..c210c6c --- /dev/null +++ b/omni_python_sdk/api/schedules/schedules_get.py @@ -0,0 +1,208 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.schedules_get_response import SchedulesGetResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + schedule_id: UUID, + *, + user_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) + params["userId"] = json_user_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/schedules/{schedule_id}".format( + schedule_id=quote(str(schedule_id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | SchedulesGetResponse | None: + if response.status_code == 200: + response_200 = SchedulesGetResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SchedulesGetResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any | SchedulesGetResponse]: + """Get schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + user_id (UUID | Unset): Membership ID of the user whose access should be checked (org API + keys only). When provided, the endpoint checks if that user has permission to view the + schedule. User-scoped API keys cannot use this parameter. Example: + 987fcdeb-51a2-43d7-9b56-254415f67890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SchedulesGetResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + user_id=user_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Any | SchedulesGetResponse | None: + """Get schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + user_id (UUID | Unset): Membership ID of the user whose access should be checked (org API + keys only). When provided, the endpoint checks if that user has permission to view the + schedule. User-scoped API keys cannot use this parameter. Example: + 987fcdeb-51a2-43d7-9b56-254415f67890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SchedulesGetResponse + """ + + return sync_detailed( + schedule_id=schedule_id, + client=client, + user_id=user_id, + ).parsed + + +async def asyncio_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Response[Any | SchedulesGetResponse]: + """Get schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + user_id (UUID | Unset): Membership ID of the user whose access should be checked (org API + keys only). When provided, the endpoint checks if that user has permission to view the + schedule. User-scoped API keys cannot use this parameter. Example: + 987fcdeb-51a2-43d7-9b56-254415f67890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SchedulesGetResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + user_id=user_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + user_id: UUID | Unset = UNSET, +) -> Any | SchedulesGetResponse | None: + """Get schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + user_id (UUID | Unset): Membership ID of the user whose access should be checked (org API + keys only). When provided, the endpoint checks if that user has permission to view the + schedule. User-scoped API keys cannot use this parameter. Example: + 987fcdeb-51a2-43d7-9b56-254415f67890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SchedulesGetResponse + """ + + return ( + await asyncio_detailed( + schedule_id=schedule_id, + client=client, + user_id=user_id, + ) + ).parsed diff --git a/omni_python_sdk/api/schedules/schedules_list.py b/omni_python_sdk/api/schedules/schedules_list.py new file mode 100644 index 0000000..c4e194e --- /dev/null +++ b/omni_python_sdk/api/schedules/schedules_list.py @@ -0,0 +1,415 @@ +from http import HTTPStatus +from typing import Any, cast +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.schedules_list_content_type import SchedulesListContentType +from ...models.schedules_list_destination import SchedulesListDestination +from ...models.schedules_list_response_200 import SchedulesListResponse200 +from ...models.schedules_list_schedule_type import SchedulesListScheduleType +from ...models.schedules_list_sort_direction import SchedulesListSortDirection +from ...models.schedules_list_sort_field import SchedulesListSortField +from ...models.schedules_list_status import SchedulesListStatus +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + cursor: str | Unset = "1", + page_size: int | Unset = 20, + sort_direction: SchedulesListSortDirection | Unset = "desc", + sort_field: SchedulesListSortField | Unset = "scheduleName", + content_type: SchedulesListContentType | Unset = UNSET, + embed_entity: str | Unset = UNSET, + destination: SchedulesListDestination | Unset = UNSET, + identifier: str | Unset = UNSET, + owner_id: UUID | Unset = UNSET, + q: str | Unset = UNSET, + schedule_type: SchedulesListScheduleType | Unset = UNSET, + status: SchedulesListStatus | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["pageSize"] = page_size + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + json_sort_field: str | Unset = UNSET + if not isinstance(sort_field, Unset): + json_sort_field = sort_field + + params["sortField"] = json_sort_field + + json_content_type: str | Unset = UNSET + if not isinstance(content_type, Unset): + json_content_type = content_type + + params["contentType"] = json_content_type + + params["embedEntity"] = embed_entity + + json_destination: str | Unset = UNSET + if not isinstance(destination, Unset): + json_destination = destination + + params["destination"] = json_destination + + params["identifier"] = identifier + + json_owner_id: str | Unset = UNSET + if not isinstance(owner_id, Unset): + json_owner_id = str(owner_id) + params["ownerId"] = json_owner_id + + params["q"] = q + + json_schedule_type: str | Unset = UNSET + if not isinstance(schedule_type, Unset): + json_schedule_type = schedule_type + + params["scheduleType"] = json_schedule_type + + json_status: str | Unset = UNSET + if not isinstance(status, Unset): + json_status = status + + params["status"] = json_status + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/schedules", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | SchedulesListResponse200 | None: + if response.status_code == 200: + response_200 = SchedulesListResponse200.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SchedulesListResponse200]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = "1", + page_size: int | Unset = 20, + sort_direction: SchedulesListSortDirection | Unset = "desc", + sort_field: SchedulesListSortField | Unset = "scheduleName", + content_type: SchedulesListContentType | Unset = UNSET, + embed_entity: str | Unset = UNSET, + destination: SchedulesListDestination | Unset = UNSET, + identifier: str | Unset = UNSET, + owner_id: UUID | Unset = UNSET, + q: str | Unset = UNSET, + schedule_type: SchedulesListScheduleType | Unset = UNSET, + status: SchedulesListStatus | Unset = UNSET, +) -> Response[Any | SchedulesListResponse200]: + """List schedules + + Args: + cursor (str | Unset): The page number for offset-based pagination. Default: '1'. Example: + 1. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (SchedulesListSortDirection | Unset): The direction to sort results (asc or + desc). Default: 'desc'. Example: desc. + sort_field (SchedulesListSortField | Unset): The field to sort results by. Valid values: + scheduleName, dashboardName, ownerName, lastRun, lastRunStatus. Default: 'scheduleName'. + Example: scheduleName. + content_type (SchedulesListContentType | Unset): Filter schedules by content type: + dashboard, single tile. Example: dashboard. + embed_entity (str | Unset): Filter schedules by embed entity. + destination (SchedulesListDestination | Unset): Filter schedules by destination type: + email, slack, webhook, sftp, s3. Example: email. + identifier (str | Unset): Filter schedules by the document's unique identifier. Can be + found in the dashboard's URL after /dashboards/. Example: 12db1a0a. + owner_id (UUID | Unset): Filter schedules by the owner's user ID. Use the List users + endpoint to retrieve user IDs. Example: 987fcdeb-51a2-43d7-9b56-254415f67890. + q (str | Unset): Search term for filtering schedules by name, dashboard name, or owner + name (case-insensitive). Example: Weekly. + schedule_type (SchedulesListScheduleType | Unset): Filter by type: alert, schedule. + Example: schedule. + status (SchedulesListStatus | Unset): Filter schedules by delivery status: success, error, + canceled, none. Example: success. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SchedulesListResponse200] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + content_type=content_type, + embed_entity=embed_entity, + destination=destination, + identifier=identifier, + owner_id=owner_id, + q=q, + schedule_type=schedule_type, + status=status, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = "1", + page_size: int | Unset = 20, + sort_direction: SchedulesListSortDirection | Unset = "desc", + sort_field: SchedulesListSortField | Unset = "scheduleName", + content_type: SchedulesListContentType | Unset = UNSET, + embed_entity: str | Unset = UNSET, + destination: SchedulesListDestination | Unset = UNSET, + identifier: str | Unset = UNSET, + owner_id: UUID | Unset = UNSET, + q: str | Unset = UNSET, + schedule_type: SchedulesListScheduleType | Unset = UNSET, + status: SchedulesListStatus | Unset = UNSET, +) -> Any | SchedulesListResponse200 | None: + """List schedules + + Args: + cursor (str | Unset): The page number for offset-based pagination. Default: '1'. Example: + 1. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (SchedulesListSortDirection | Unset): The direction to sort results (asc or + desc). Default: 'desc'. Example: desc. + sort_field (SchedulesListSortField | Unset): The field to sort results by. Valid values: + scheduleName, dashboardName, ownerName, lastRun, lastRunStatus. Default: 'scheduleName'. + Example: scheduleName. + content_type (SchedulesListContentType | Unset): Filter schedules by content type: + dashboard, single tile. Example: dashboard. + embed_entity (str | Unset): Filter schedules by embed entity. + destination (SchedulesListDestination | Unset): Filter schedules by destination type: + email, slack, webhook, sftp, s3. Example: email. + identifier (str | Unset): Filter schedules by the document's unique identifier. Can be + found in the dashboard's URL after /dashboards/. Example: 12db1a0a. + owner_id (UUID | Unset): Filter schedules by the owner's user ID. Use the List users + endpoint to retrieve user IDs. Example: 987fcdeb-51a2-43d7-9b56-254415f67890. + q (str | Unset): Search term for filtering schedules by name, dashboard name, or owner + name (case-insensitive). Example: Weekly. + schedule_type (SchedulesListScheduleType | Unset): Filter by type: alert, schedule. + Example: schedule. + status (SchedulesListStatus | Unset): Filter schedules by delivery status: success, error, + canceled, none. Example: success. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SchedulesListResponse200 + """ + + return sync_detailed( + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + content_type=content_type, + embed_entity=embed_entity, + destination=destination, + identifier=identifier, + owner_id=owner_id, + q=q, + schedule_type=schedule_type, + status=status, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = "1", + page_size: int | Unset = 20, + sort_direction: SchedulesListSortDirection | Unset = "desc", + sort_field: SchedulesListSortField | Unset = "scheduleName", + content_type: SchedulesListContentType | Unset = UNSET, + embed_entity: str | Unset = UNSET, + destination: SchedulesListDestination | Unset = UNSET, + identifier: str | Unset = UNSET, + owner_id: UUID | Unset = UNSET, + q: str | Unset = UNSET, + schedule_type: SchedulesListScheduleType | Unset = UNSET, + status: SchedulesListStatus | Unset = UNSET, +) -> Response[Any | SchedulesListResponse200]: + """List schedules + + Args: + cursor (str | Unset): The page number for offset-based pagination. Default: '1'. Example: + 1. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (SchedulesListSortDirection | Unset): The direction to sort results (asc or + desc). Default: 'desc'. Example: desc. + sort_field (SchedulesListSortField | Unset): The field to sort results by. Valid values: + scheduleName, dashboardName, ownerName, lastRun, lastRunStatus. Default: 'scheduleName'. + Example: scheduleName. + content_type (SchedulesListContentType | Unset): Filter schedules by content type: + dashboard, single tile. Example: dashboard. + embed_entity (str | Unset): Filter schedules by embed entity. + destination (SchedulesListDestination | Unset): Filter schedules by destination type: + email, slack, webhook, sftp, s3. Example: email. + identifier (str | Unset): Filter schedules by the document's unique identifier. Can be + found in the dashboard's URL after /dashboards/. Example: 12db1a0a. + owner_id (UUID | Unset): Filter schedules by the owner's user ID. Use the List users + endpoint to retrieve user IDs. Example: 987fcdeb-51a2-43d7-9b56-254415f67890. + q (str | Unset): Search term for filtering schedules by name, dashboard name, or owner + name (case-insensitive). Example: Weekly. + schedule_type (SchedulesListScheduleType | Unset): Filter by type: alert, schedule. + Example: schedule. + status (SchedulesListStatus | Unset): Filter schedules by delivery status: success, error, + canceled, none. Example: success. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SchedulesListResponse200] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + content_type=content_type, + embed_entity=embed_entity, + destination=destination, + identifier=identifier, + owner_id=owner_id, + q=q, + schedule_type=schedule_type, + status=status, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = "1", + page_size: int | Unset = 20, + sort_direction: SchedulesListSortDirection | Unset = "desc", + sort_field: SchedulesListSortField | Unset = "scheduleName", + content_type: SchedulesListContentType | Unset = UNSET, + embed_entity: str | Unset = UNSET, + destination: SchedulesListDestination | Unset = UNSET, + identifier: str | Unset = UNSET, + owner_id: UUID | Unset = UNSET, + q: str | Unset = UNSET, + schedule_type: SchedulesListScheduleType | Unset = UNSET, + status: SchedulesListStatus | Unset = UNSET, +) -> Any | SchedulesListResponse200 | None: + """List schedules + + Args: + cursor (str | Unset): The page number for offset-based pagination. Default: '1'. Example: + 1. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (SchedulesListSortDirection | Unset): The direction to sort results (asc or + desc). Default: 'desc'. Example: desc. + sort_field (SchedulesListSortField | Unset): The field to sort results by. Valid values: + scheduleName, dashboardName, ownerName, lastRun, lastRunStatus. Default: 'scheduleName'. + Example: scheduleName. + content_type (SchedulesListContentType | Unset): Filter schedules by content type: + dashboard, single tile. Example: dashboard. + embed_entity (str | Unset): Filter schedules by embed entity. + destination (SchedulesListDestination | Unset): Filter schedules by destination type: + email, slack, webhook, sftp, s3. Example: email. + identifier (str | Unset): Filter schedules by the document's unique identifier. Can be + found in the dashboard's URL after /dashboards/. Example: 12db1a0a. + owner_id (UUID | Unset): Filter schedules by the owner's user ID. Use the List users + endpoint to retrieve user IDs. Example: 987fcdeb-51a2-43d7-9b56-254415f67890. + q (str | Unset): Search term for filtering schedules by name, dashboard name, or owner + name (case-insensitive). Example: Weekly. + schedule_type (SchedulesListScheduleType | Unset): Filter by type: alert, schedule. + Example: schedule. + status (SchedulesListStatus | Unset): Filter schedules by delivery status: success, error, + canceled, none. Example: success. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SchedulesListResponse200 + """ + + return ( + await asyncio_detailed( + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + content_type=content_type, + embed_entity=embed_entity, + destination=destination, + identifier=identifier, + owner_id=owner_id, + q=q, + schedule_type=schedule_type, + status=status, + ) + ).parsed diff --git a/omni_python_sdk/api/schedules/schedules_pause.py b/omni_python_sdk/api/schedules/schedules_pause.py new file mode 100644 index 0000000..8f5610d --- /dev/null +++ b/omni_python_sdk/api/schedules/schedules_pause.py @@ -0,0 +1,170 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.success_response import SuccessResponse +from ...types import Response + + +def _get_kwargs( + schedule_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/schedules/{schedule_id}/pause".format( + schedule_id=quote(str(schedule_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Pause schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Pause schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + schedule_id=schedule_id, + client=client, + ).parsed + + +async def asyncio_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Pause schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Pause schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + schedule_id=schedule_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/schedules/schedules_recipients_get.py b/omni_python_sdk/api/schedules/schedules_recipients_get.py new file mode 100644 index 0000000..790f68e --- /dev/null +++ b/omni_python_sdk/api/schedules/schedules_recipients_get.py @@ -0,0 +1,172 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.schedules_recipients_get_response import SchedulesRecipientsGetResponse +from ...types import Response + + +def _get_kwargs( + schedule_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/schedules/{schedule_id}/recipients".format( + schedule_id=quote(str(schedule_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | SchedulesRecipientsGetResponse | None: + if response.status_code == 200: + response_200 = SchedulesRecipientsGetResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SchedulesRecipientsGetResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SchedulesRecipientsGetResponse]: + """Get schedule recipients + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SchedulesRecipientsGetResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SchedulesRecipientsGetResponse | None: + """Get schedule recipients + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SchedulesRecipientsGetResponse + """ + + return sync_detailed( + schedule_id=schedule_id, + client=client, + ).parsed + + +async def asyncio_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SchedulesRecipientsGetResponse]: + """Get schedule recipients + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SchedulesRecipientsGetResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SchedulesRecipientsGetResponse | None: + """Get schedule recipients + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SchedulesRecipientsGetResponse + """ + + return ( + await asyncio_detailed( + schedule_id=schedule_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/schedules/schedules_remove_recipients.py b/omni_python_sdk/api/schedules/schedules_remove_recipients.py new file mode 100644 index 0000000..fa74802 --- /dev/null +++ b/omni_python_sdk/api/schedules/schedules_remove_recipients.py @@ -0,0 +1,198 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.schedules_remove_recipients_body import SchedulesRemoveRecipientsBody +from ...models.schedules_remove_recipients_response import SchedulesRemoveRecipientsResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + schedule_id: UUID, + *, + body: SchedulesRemoveRecipientsBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/schedules/{schedule_id}/remove-recipients".format( + schedule_id=quote(str(schedule_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | SchedulesRemoveRecipientsResponse | None: + if response.status_code == 200: + response_200 = SchedulesRemoveRecipientsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SchedulesRemoveRecipientsResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: SchedulesRemoveRecipientsBody | Unset = UNSET, +) -> Response[Any | SchedulesRemoveRecipientsResponse]: + """Remove schedule recipients + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + body (SchedulesRemoveRecipientsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SchedulesRemoveRecipientsResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: SchedulesRemoveRecipientsBody | Unset = UNSET, +) -> Any | SchedulesRemoveRecipientsResponse | None: + """Remove schedule recipients + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + body (SchedulesRemoveRecipientsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SchedulesRemoveRecipientsResponse + """ + + return sync_detailed( + schedule_id=schedule_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: SchedulesRemoveRecipientsBody | Unset = UNSET, +) -> Response[Any | SchedulesRemoveRecipientsResponse]: + """Remove schedule recipients + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + body (SchedulesRemoveRecipientsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SchedulesRemoveRecipientsResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: SchedulesRemoveRecipientsBody | Unset = UNSET, +) -> Any | SchedulesRemoveRecipientsResponse | None: + """Remove schedule recipients + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + body (SchedulesRemoveRecipientsBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SchedulesRemoveRecipientsResponse + """ + + return ( + await asyncio_detailed( + schedule_id=schedule_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/schedules/schedules_resume.py b/omni_python_sdk/api/schedules/schedules_resume.py new file mode 100644 index 0000000..d357b35 --- /dev/null +++ b/omni_python_sdk/api/schedules/schedules_resume.py @@ -0,0 +1,170 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.success_response import SuccessResponse +from ...types import Response + + +def _get_kwargs( + schedule_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/schedules/{schedule_id}/resume".format( + schedule_id=quote(str(schedule_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Resume schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Resume schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + schedule_id=schedule_id, + client=client, + ).parsed + + +async def asyncio_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Resume schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Resume schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + schedule_id=schedule_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/schedules/schedules_transfer_ownership.py b/omni_python_sdk/api/schedules/schedules_transfer_ownership.py new file mode 100644 index 0000000..5ca77a1 --- /dev/null +++ b/omni_python_sdk/api/schedules/schedules_transfer_ownership.py @@ -0,0 +1,196 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.schedules_transfer_ownership_body import SchedulesTransferOwnershipBody +from ...models.success_response import SuccessResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + schedule_id: UUID, + *, + body: SchedulesTransferOwnershipBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/schedules/{schedule_id}/transfer-ownership".format( + schedule_id=quote(str(schedule_id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: SchedulesTransferOwnershipBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Transfer schedule ownership + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + body (SchedulesTransferOwnershipBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: SchedulesTransferOwnershipBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Transfer schedule ownership + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + body (SchedulesTransferOwnershipBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + schedule_id=schedule_id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: SchedulesTransferOwnershipBody | Unset = UNSET, +) -> Response[Any | SuccessResponse]: + """Transfer schedule ownership + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + body (SchedulesTransferOwnershipBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, + body: SchedulesTransferOwnershipBody | Unset = UNSET, +) -> Any | SuccessResponse | None: + """Transfer schedule ownership + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + body (SchedulesTransferOwnershipBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + schedule_id=schedule_id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/schedules/schedules_trigger.py b/omni_python_sdk/api/schedules/schedules_trigger.py new file mode 100644 index 0000000..bb8408f --- /dev/null +++ b/omni_python_sdk/api/schedules/schedules_trigger.py @@ -0,0 +1,174 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.success_response import SuccessResponse +from ...types import Response + + +def _get_kwargs( + schedule_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/schedules/{schedule_id}/trigger".format( + schedule_id=quote(str(schedule_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuccessResponse | None: + if response.status_code == 200: + response_200 = SuccessResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuccessResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Trigger schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Trigger schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return sync_detailed( + schedule_id=schedule_id, + client=client, + ).parsed + + +async def asyncio_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuccessResponse]: + """Trigger schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuccessResponse] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuccessResponse | None: + """Trigger schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuccessResponse + """ + + return ( + await asyncio_detailed( + schedule_id=schedule_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/schedules/schedules_update.py b/omni_python_sdk/api/schedules/schedules_update.py new file mode 100644 index 0000000..bda22f3 --- /dev/null +++ b/omni_python_sdk/api/schedules/schedules_update.py @@ -0,0 +1,113 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import Response + + +def _get_kwargs( + schedule_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/v1/schedules/{schedule_id}".format( + schedule_id=quote(str(schedule_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None: + if response.status_code == 200: + return None + + if response.status_code == 400: + return None + + if response.status_code == 401: + return None + + if response.status_code == 403: + return None + + if response.status_code == 404: + return None + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any]: + """Update schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + schedule_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any]: + """Update schedule + + Args: + schedule_id (UUID): The UUID of the scheduled task. Can be found in the schedule's URL + after /schedules/. Example: 123e4567-e89b-12d3-a456-426614174000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + schedule_id=schedule_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/omni_python_sdk/api/scim/__init__.py b/omni_python_sdk/api/scim/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/scim/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/scim/scim_embed_users_delete.py b/omni_python_sdk/api/scim/scim_embed_users_delete.py new file mode 100644 index 0000000..940dda4 --- /dev/null +++ b/omni_python_sdk/api/scim/scim_embed_users_delete.py @@ -0,0 +1,111 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import Response + + +def _get_kwargs( + id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/scim/v2/embed/Users/{id}".format( + id=quote(str(id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None: + if response.status_code == 204: + return None + + if response.status_code == 401: + return None + + if response.status_code == 404: + return None + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any]: + """Delete embed user + + Permanently delete an embed user. Unlike standard SCIM user deletion which soft-deletes, this + performs a hard delete. + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any]: + """Delete embed user + + Permanently delete an embed user. Unlike standard SCIM user deletion which soft-deletes, this + performs a hard delete. + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/omni_python_sdk/api/scim/scim_embed_users_get.py b/omni_python_sdk/api/scim/scim_embed_users_get.py new file mode 100644 index 0000000..0c90cc7 --- /dev/null +++ b/omni_python_sdk/api/scim/scim_embed_users_get.py @@ -0,0 +1,170 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.scim_user_response import ScimUserResponse +from ...types import Response + + +def _get_kwargs( + id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/scim/v2/embed/Users/{id}".format( + id=quote(str(id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | ScimUserResponse | None: + if response.status_code == 200: + response_200 = ScimUserResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScimUserResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ScimUserResponse]: + """Get embed user + + Get details for a specific embed user. + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUserResponse] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ScimUserResponse | None: + """Get embed user + + Get details for a specific embed user. + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUserResponse + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ScimUserResponse]: + """Get embed user + + Get details for a specific embed user. + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUserResponse] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ScimUserResponse | None: + """Get embed user + + Get details for a specific embed user. + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUserResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/scim/scim_embed_users_list.py b/omni_python_sdk/api/scim/scim_embed_users_list.py new file mode 100644 index 0000000..767879b --- /dev/null +++ b/omni_python_sdk/api/scim/scim_embed_users_list.py @@ -0,0 +1,206 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.scim_users_list_response import ScimUsersListResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + count: str | Unset = "100", + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["count"] = count + + params["filter"] = filter_ + + params["startIndex"] = start_index + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/scim/v2/embed/Users", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ScimUsersListResponse | None: + if response.status_code == 200: + response_200 = ScimUsersListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScimUsersListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + count: str | Unset = "100", + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> Response[Any | ScimUsersListResponse]: + """List embed users + + List embed users. Embed users are externally-managed users created via the embed SSO flow. + + Args: + count (str | Unset): Maximum number of results to return Default: '100'. Example: 100. + filter_ (str | Unset): SCIM filter expression Example: userName eq "user@example.com". + start_index (str | Unset): Index of the first result to return (1-based) Default: '1'. + Example: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUsersListResponse] + """ + + kwargs = _get_kwargs( + count=count, + filter_=filter_, + start_index=start_index, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + count: str | Unset = "100", + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> Any | ScimUsersListResponse | None: + """List embed users + + List embed users. Embed users are externally-managed users created via the embed SSO flow. + + Args: + count (str | Unset): Maximum number of results to return Default: '100'. Example: 100. + filter_ (str | Unset): SCIM filter expression Example: userName eq "user@example.com". + start_index (str | Unset): Index of the first result to return (1-based) Default: '1'. + Example: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUsersListResponse + """ + + return sync_detailed( + client=client, + count=count, + filter_=filter_, + start_index=start_index, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + count: str | Unset = "100", + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> Response[Any | ScimUsersListResponse]: + """List embed users + + List embed users. Embed users are externally-managed users created via the embed SSO flow. + + Args: + count (str | Unset): Maximum number of results to return Default: '100'. Example: 100. + filter_ (str | Unset): SCIM filter expression Example: userName eq "user@example.com". + start_index (str | Unset): Index of the first result to return (1-based) Default: '1'. + Example: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUsersListResponse] + """ + + kwargs = _get_kwargs( + count=count, + filter_=filter_, + start_index=start_index, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + count: str | Unset = "100", + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> Any | ScimUsersListResponse | None: + """List embed users + + List embed users. Embed users are externally-managed users created via the embed SSO flow. + + Args: + count (str | Unset): Maximum number of results to return Default: '100'. Example: 100. + filter_ (str | Unset): SCIM filter expression Example: userName eq "user@example.com". + start_index (str | Unset): Index of the first result to return (1-based) Default: '1'. + Example: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUsersListResponse + """ + + return ( + await asyncio_detailed( + client=client, + count=count, + filter_=filter_, + start_index=start_index, + ) + ).parsed diff --git a/omni_python_sdk/api/scim/scim_groups_create.py b/omni_python_sdk/api/scim/scim_groups_create.py new file mode 100644 index 0000000..5365c12 --- /dev/null +++ b/omni_python_sdk/api/scim/scim_groups_create.py @@ -0,0 +1,173 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.scim_group_response import ScimGroupResponse +from ...models.scim_groups_create_body import ScimGroupsCreateBody +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: ScimGroupsCreateBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/scim/v2/Groups", + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ScimGroupResponse | None: + if response.status_code == 201: + response_201 = ScimGroupResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScimGroupResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: ScimGroupsCreateBody | Unset = UNSET, +) -> Response[Any | ScimGroupResponse]: + """Create SCIM group + + Args: + body (ScimGroupsCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimGroupResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: ScimGroupsCreateBody | Unset = UNSET, +) -> Any | ScimGroupResponse | None: + """Create SCIM group + + Args: + body (ScimGroupsCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimGroupResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: ScimGroupsCreateBody | Unset = UNSET, +) -> Response[Any | ScimGroupResponse]: + """Create SCIM group + + Args: + body (ScimGroupsCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimGroupResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: ScimGroupsCreateBody | Unset = UNSET, +) -> Any | ScimGroupResponse | None: + """Create SCIM group + + Args: + body (ScimGroupsCreateBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimGroupResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/scim/scim_groups_delete.py b/omni_python_sdk/api/scim/scim_groups_delete.py new file mode 100644 index 0000000..edd9a38 --- /dev/null +++ b/omni_python_sdk/api/scim/scim_groups_delete.py @@ -0,0 +1,104 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import Response + + +def _get_kwargs( + mini_uuid: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/scim/v2/Groups/{mini_uuid}".format( + mini_uuid=quote(str(mini_uuid), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None: + if response.status_code == 204: + return None + + if response.status_code == 401: + return None + + if response.status_code == 404: + return None + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any]: + """Delete SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + mini_uuid=mini_uuid, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any]: + """Delete SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + mini_uuid=mini_uuid, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/omni_python_sdk/api/scim/scim_groups_get.py b/omni_python_sdk/api/scim/scim_groups_get.py new file mode 100644 index 0000000..c289ffe --- /dev/null +++ b/omni_python_sdk/api/scim/scim_groups_get.py @@ -0,0 +1,195 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.scim_group_response import ScimGroupResponse +from ...models.scim_groups_get_excluded_attributes import ( + ScimGroupsGetExcludedAttributes, +) +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + mini_uuid: str, + *, + excluded_attributes: ScimGroupsGetExcludedAttributes | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_excluded_attributes: str | Unset = UNSET + if not isinstance(excluded_attributes, Unset): + json_excluded_attributes = excluded_attributes + + params["excludedAttributes"] = json_excluded_attributes + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/scim/v2/Groups/{mini_uuid}".format( + mini_uuid=quote(str(mini_uuid), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ScimGroupResponse | None: + if response.status_code == 200: + response_200 = ScimGroupResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScimGroupResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, + excluded_attributes: ScimGroupsGetExcludedAttributes | Unset = UNSET, +) -> Response[Any | ScimGroupResponse]: + """Get SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + excluded_attributes (ScimGroupsGetExcludedAttributes | Unset): Attributes to exclude from + the response Example: members. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimGroupResponse] + """ + + kwargs = _get_kwargs( + mini_uuid=mini_uuid, + excluded_attributes=excluded_attributes, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, + excluded_attributes: ScimGroupsGetExcludedAttributes | Unset = UNSET, +) -> Any | ScimGroupResponse | None: + """Get SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + excluded_attributes (ScimGroupsGetExcludedAttributes | Unset): Attributes to exclude from + the response Example: members. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimGroupResponse + """ + + return sync_detailed( + mini_uuid=mini_uuid, + client=client, + excluded_attributes=excluded_attributes, + ).parsed + + +async def asyncio_detailed( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, + excluded_attributes: ScimGroupsGetExcludedAttributes | Unset = UNSET, +) -> Response[Any | ScimGroupResponse]: + """Get SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + excluded_attributes (ScimGroupsGetExcludedAttributes | Unset): Attributes to exclude from + the response Example: members. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimGroupResponse] + """ + + kwargs = _get_kwargs( + mini_uuid=mini_uuid, + excluded_attributes=excluded_attributes, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, + excluded_attributes: ScimGroupsGetExcludedAttributes | Unset = UNSET, +) -> Any | ScimGroupResponse | None: + """Get SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + excluded_attributes (ScimGroupsGetExcludedAttributes | Unset): Attributes to exclude from + the response Example: members. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimGroupResponse + """ + + return ( + await asyncio_detailed( + mini_uuid=mini_uuid, + client=client, + excluded_attributes=excluded_attributes, + ) + ).parsed diff --git a/omni_python_sdk/api/scim/scim_groups_list.py b/omni_python_sdk/api/scim/scim_groups_list.py new file mode 100644 index 0000000..cd5183e --- /dev/null +++ b/omni_python_sdk/api/scim/scim_groups_list.py @@ -0,0 +1,224 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.scim_groups_list_excluded_attributes import ( + ScimGroupsListExcludedAttributes, +) +from ...models.scim_groups_list_response import ScimGroupsListResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + count: str | Unset = "100", + excluded_attributes: ScimGroupsListExcludedAttributes | Unset = UNSET, + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["count"] = count + + json_excluded_attributes: str | Unset = UNSET + if not isinstance(excluded_attributes, Unset): + json_excluded_attributes = excluded_attributes + + params["excludedAttributes"] = json_excluded_attributes + + params["filter"] = filter_ + + params["startIndex"] = start_index + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/scim/v2/Groups", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ScimGroupsListResponse | None: + if response.status_code == 200: + response_200 = ScimGroupsListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScimGroupsListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + count: str | Unset = "100", + excluded_attributes: ScimGroupsListExcludedAttributes | Unset = UNSET, + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> Response[Any | ScimGroupsListResponse]: + """List SCIM groups + + Args: + count (str | Unset): Maximum number of results to return Default: '100'. Example: 100. + excluded_attributes (ScimGroupsListExcludedAttributes | Unset): Attributes to exclude from + the response Example: members. + filter_ (str | Unset): SCIM filter expression Example: displayName eq "Engineering". + start_index (str | Unset): Index of the first result to return (1-based) Default: '1'. + Example: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimGroupsListResponse] + """ + + kwargs = _get_kwargs( + count=count, + excluded_attributes=excluded_attributes, + filter_=filter_, + start_index=start_index, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + count: str | Unset = "100", + excluded_attributes: ScimGroupsListExcludedAttributes | Unset = UNSET, + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> Any | ScimGroupsListResponse | None: + """List SCIM groups + + Args: + count (str | Unset): Maximum number of results to return Default: '100'. Example: 100. + excluded_attributes (ScimGroupsListExcludedAttributes | Unset): Attributes to exclude from + the response Example: members. + filter_ (str | Unset): SCIM filter expression Example: displayName eq "Engineering". + start_index (str | Unset): Index of the first result to return (1-based) Default: '1'. + Example: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimGroupsListResponse + """ + + return sync_detailed( + client=client, + count=count, + excluded_attributes=excluded_attributes, + filter_=filter_, + start_index=start_index, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + count: str | Unset = "100", + excluded_attributes: ScimGroupsListExcludedAttributes | Unset = UNSET, + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> Response[Any | ScimGroupsListResponse]: + """List SCIM groups + + Args: + count (str | Unset): Maximum number of results to return Default: '100'. Example: 100. + excluded_attributes (ScimGroupsListExcludedAttributes | Unset): Attributes to exclude from + the response Example: members. + filter_ (str | Unset): SCIM filter expression Example: displayName eq "Engineering". + start_index (str | Unset): Index of the first result to return (1-based) Default: '1'. + Example: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimGroupsListResponse] + """ + + kwargs = _get_kwargs( + count=count, + excluded_attributes=excluded_attributes, + filter_=filter_, + start_index=start_index, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + count: str | Unset = "100", + excluded_attributes: ScimGroupsListExcludedAttributes | Unset = UNSET, + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> Any | ScimGroupsListResponse | None: + """List SCIM groups + + Args: + count (str | Unset): Maximum number of results to return Default: '100'. Example: 100. + excluded_attributes (ScimGroupsListExcludedAttributes | Unset): Attributes to exclude from + the response Example: members. + filter_ (str | Unset): SCIM filter expression Example: displayName eq "Engineering". + start_index (str | Unset): Index of the first result to return (1-based) Default: '1'. + Example: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimGroupsListResponse + """ + + return ( + await asyncio_detailed( + client=client, + count=count, + excluded_attributes=excluded_attributes, + filter_=filter_, + start_index=start_index, + ) + ).parsed diff --git a/omni_python_sdk/api/scim/scim_groups_replace.py b/omni_python_sdk/api/scim/scim_groups_replace.py new file mode 100644 index 0000000..940d79c --- /dev/null +++ b/omni_python_sdk/api/scim/scim_groups_replace.py @@ -0,0 +1,189 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.scim_group_response import ScimGroupResponse +from ...models.scim_groups_replace_body import ScimGroupsReplaceBody +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + mini_uuid: str, + *, + body: ScimGroupsReplaceBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/scim/v2/Groups/{mini_uuid}".format( + mini_uuid=quote(str(mini_uuid), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ScimGroupResponse | None: + if response.status_code == 200: + response_200 = ScimGroupResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScimGroupResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, + body: ScimGroupsReplaceBody | Unset = UNSET, +) -> Response[Any | ScimGroupResponse]: + """Replace SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + body (ScimGroupsReplaceBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimGroupResponse] + """ + + kwargs = _get_kwargs( + mini_uuid=mini_uuid, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, + body: ScimGroupsReplaceBody | Unset = UNSET, +) -> Any | ScimGroupResponse | None: + """Replace SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + body (ScimGroupsReplaceBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimGroupResponse + """ + + return sync_detailed( + mini_uuid=mini_uuid, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, + body: ScimGroupsReplaceBody | Unset = UNSET, +) -> Response[Any | ScimGroupResponse]: + """Replace SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + body (ScimGroupsReplaceBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimGroupResponse] + """ + + kwargs = _get_kwargs( + mini_uuid=mini_uuid, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, + body: ScimGroupsReplaceBody | Unset = UNSET, +) -> Any | ScimGroupResponse | None: + """Replace SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + body (ScimGroupsReplaceBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimGroupResponse + """ + + return ( + await asyncio_detailed( + mini_uuid=mini_uuid, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/scim/scim_groups_update.py b/omni_python_sdk/api/scim/scim_groups_update.py new file mode 100644 index 0000000..95c8588 --- /dev/null +++ b/omni_python_sdk/api/scim/scim_groups_update.py @@ -0,0 +1,189 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.scim_group_response import ScimGroupResponse +from ...models.scim_groups_patch_body import ScimGroupsPatchBody +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + mini_uuid: str, + *, + body: ScimGroupsPatchBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/scim/v2/Groups/{mini_uuid}".format( + mini_uuid=quote(str(mini_uuid), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ScimGroupResponse | None: + if response.status_code == 200: + response_200 = ScimGroupResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScimGroupResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, + body: ScimGroupsPatchBody | Unset = UNSET, +) -> Response[Any | ScimGroupResponse]: + """Update SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + body (ScimGroupsPatchBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimGroupResponse] + """ + + kwargs = _get_kwargs( + mini_uuid=mini_uuid, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, + body: ScimGroupsPatchBody | Unset = UNSET, +) -> Any | ScimGroupResponse | None: + """Update SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + body (ScimGroupsPatchBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimGroupResponse + """ + + return sync_detailed( + mini_uuid=mini_uuid, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, + body: ScimGroupsPatchBody | Unset = UNSET, +) -> Response[Any | ScimGroupResponse]: + """Update SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + body (ScimGroupsPatchBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimGroupResponse] + """ + + kwargs = _get_kwargs( + mini_uuid=mini_uuid, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + mini_uuid: str, + *, + client: AuthenticatedClient | Client, + body: ScimGroupsPatchBody | Unset = UNSET, +) -> Any | ScimGroupResponse | None: + """Update SCIM group + + Args: + mini_uuid (str): Short identifier of the group Example: abc123. + body (ScimGroupsPatchBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimGroupResponse + """ + + return ( + await asyncio_detailed( + mini_uuid=mini_uuid, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/scim/scim_users_create.py b/omni_python_sdk/api/scim/scim_users_create.py new file mode 100644 index 0000000..2f3585b --- /dev/null +++ b/omni_python_sdk/api/scim/scim_users_create.py @@ -0,0 +1,171 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.scim_user_create_request import ScimUserCreateRequest +from ...models.scim_user_response import ScimUserResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: ScimUserCreateRequest | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/scim/v2/Users", + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | ScimUserResponse | None: + if response.status_code == 201: + response_201 = ScimUserResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScimUserResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: ScimUserCreateRequest | Unset = UNSET, +) -> Response[Any | ScimUserResponse]: + """Create SCIM user + + Args: + body (ScimUserCreateRequest | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUserResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: ScimUserCreateRequest | Unset = UNSET, +) -> Any | ScimUserResponse | None: + """Create SCIM user + + Args: + body (ScimUserCreateRequest | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUserResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: ScimUserCreateRequest | Unset = UNSET, +) -> Response[Any | ScimUserResponse]: + """Create SCIM user + + Args: + body (ScimUserCreateRequest | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUserResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: ScimUserCreateRequest | Unset = UNSET, +) -> Any | ScimUserResponse | None: + """Create SCIM user + + Args: + body (ScimUserCreateRequest | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUserResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/scim/scim_users_delete.py b/omni_python_sdk/api/scim/scim_users_delete.py new file mode 100644 index 0000000..bb7066a --- /dev/null +++ b/omni_python_sdk/api/scim/scim_users_delete.py @@ -0,0 +1,105 @@ +from http import HTTPStatus +from typing import Any +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...types import Response + + +def _get_kwargs( + id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/scim/v2/Users/{id}".format( + id=quote(str(id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | None: + if response.status_code == 204: + return None + + if response.status_code == 401: + return None + + if response.status_code == 404: + return None + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any]: + """Delete SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any]: + """Delete SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) diff --git a/omni_python_sdk/api/scim/scim_users_get.py b/omni_python_sdk/api/scim/scim_users_get.py new file mode 100644 index 0000000..cc4966f --- /dev/null +++ b/omni_python_sdk/api/scim/scim_users_get.py @@ -0,0 +1,162 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.scim_user_response import ScimUserResponse +from ...types import Response + + +def _get_kwargs( + id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/scim/v2/Users/{id}".format( + id=quote(str(id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | ScimUserResponse | None: + if response.status_code == 200: + response_200 = ScimUserResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScimUserResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ScimUserResponse]: + """Get SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUserResponse] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ScimUserResponse | None: + """Get SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUserResponse + """ + + return sync_detailed( + id=id, + client=client, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | ScimUserResponse]: + """Get SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUserResponse] + """ + + kwargs = _get_kwargs( + id=id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | ScimUserResponse | None: + """Get SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUserResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/scim/scim_users_list.py b/omni_python_sdk/api/scim/scim_users_list.py new file mode 100644 index 0000000..a22523d --- /dev/null +++ b/omni_python_sdk/api/scim/scim_users_list.py @@ -0,0 +1,198 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.scim_users_list_response import ScimUsersListResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + count: str | Unset = "100", + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["count"] = count + + params["filter"] = filter_ + + params["startIndex"] = start_index + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/scim/v2/Users", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | ScimUsersListResponse | None: + if response.status_code == 200: + response_200 = ScimUsersListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScimUsersListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + count: str | Unset = "100", + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> Response[Any | ScimUsersListResponse]: + """List SCIM users + + Args: + count (str | Unset): Maximum number of results to return Default: '100'. Example: 100. + filter_ (str | Unset): SCIM filter expression Example: userName eq "user@example.com". + start_index (str | Unset): Index of the first result to return (1-based) Default: '1'. + Example: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUsersListResponse] + """ + + kwargs = _get_kwargs( + count=count, + filter_=filter_, + start_index=start_index, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + count: str | Unset = "100", + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> Any | ScimUsersListResponse | None: + """List SCIM users + + Args: + count (str | Unset): Maximum number of results to return Default: '100'. Example: 100. + filter_ (str | Unset): SCIM filter expression Example: userName eq "user@example.com". + start_index (str | Unset): Index of the first result to return (1-based) Default: '1'. + Example: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUsersListResponse + """ + + return sync_detailed( + client=client, + count=count, + filter_=filter_, + start_index=start_index, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + count: str | Unset = "100", + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> Response[Any | ScimUsersListResponse]: + """List SCIM users + + Args: + count (str | Unset): Maximum number of results to return Default: '100'. Example: 100. + filter_ (str | Unset): SCIM filter expression Example: userName eq "user@example.com". + start_index (str | Unset): Index of the first result to return (1-based) Default: '1'. + Example: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUsersListResponse] + """ + + kwargs = _get_kwargs( + count=count, + filter_=filter_, + start_index=start_index, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + count: str | Unset = "100", + filter_: str | Unset = UNSET, + start_index: str | Unset = "1", +) -> Any | ScimUsersListResponse | None: + """List SCIM users + + Args: + count (str | Unset): Maximum number of results to return Default: '100'. Example: 100. + filter_ (str | Unset): SCIM filter expression Example: userName eq "user@example.com". + start_index (str | Unset): Index of the first result to return (1-based) Default: '1'. + Example: 1. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUsersListResponse + """ + + return ( + await asyncio_detailed( + client=client, + count=count, + filter_=filter_, + start_index=start_index, + ) + ).parsed diff --git a/omni_python_sdk/api/scim/scim_users_replace.py b/omni_python_sdk/api/scim/scim_users_replace.py new file mode 100644 index 0000000..2bf929c --- /dev/null +++ b/omni_python_sdk/api/scim/scim_users_replace.py @@ -0,0 +1,188 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.scim_user_put_request import ScimUserPutRequest +from ...models.scim_user_response import ScimUserResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: UUID, + *, + body: ScimUserPutRequest | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "put", + "url": "/api/scim/v2/Users/{id}".format( + id=quote(str(id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | ScimUserResponse | None: + if response.status_code == 200: + response_200 = ScimUserResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScimUserResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ScimUserPutRequest | Unset = UNSET, +) -> Response[Any | ScimUserResponse]: + """Replace SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ScimUserPutRequest | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUserResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ScimUserPutRequest | Unset = UNSET, +) -> Any | ScimUserResponse | None: + """Replace SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ScimUserPutRequest | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUserResponse + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ScimUserPutRequest | Unset = UNSET, +) -> Response[Any | ScimUserResponse]: + """Replace SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ScimUserPutRequest | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUserResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ScimUserPutRequest | Unset = UNSET, +) -> Any | ScimUserResponse | None: + """Replace SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ScimUserPutRequest | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUserResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/scim/scim_users_update.py b/omni_python_sdk/api/scim/scim_users_update.py new file mode 100644 index 0000000..f3416f7 --- /dev/null +++ b/omni_python_sdk/api/scim/scim_users_update.py @@ -0,0 +1,188 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.scim_user_patch_request import ScimUserPatchRequest +from ...models.scim_user_response import ScimUserResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: UUID, + *, + body: ScimUserPatchRequest | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/scim/v2/Users/{id}".format( + id=quote(str(id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | ScimUserResponse | None: + if response.status_code == 200: + response_200 = ScimUserResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | ScimUserResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ScimUserPatchRequest | Unset = UNSET, +) -> Response[Any | ScimUserResponse]: + """Update SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ScimUserPatchRequest | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUserResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ScimUserPatchRequest | Unset = UNSET, +) -> Any | ScimUserResponse | None: + """Update SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ScimUserPatchRequest | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUserResponse + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ScimUserPatchRequest | Unset = UNSET, +) -> Response[Any | ScimUserResponse]: + """Update SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ScimUserPatchRequest | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | ScimUserResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: ScimUserPatchRequest | Unset = UNSET, +) -> Any | ScimUserResponse | None: + """Update SCIM user + + Args: + id (UUID): SCIM user ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (ScimUserPatchRequest | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | ScimUserResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/unstable/__init__.py b/omni_python_sdk/api/unstable/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/unstable/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/unstable/unstable_documents_export.py b/omni_python_sdk/api/unstable/unstable_documents_export.py new file mode 100644 index 0000000..c71dcc9 --- /dev/null +++ b/omni_python_sdk/api/unstable/unstable_documents_export.py @@ -0,0 +1,167 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.document_export_response import DocumentExportResponse +from ...types import Response + + +def _get_kwargs( + identifier: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/unstable/documents/{identifier}/export".format( + identifier=quote(str(identifier), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentExportResponse | None: + if response.status_code == 200: + response_200 = DocumentExportResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentExportResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | DocumentExportResponse]: + """Export document (unstable) + + Args: + identifier (str): Document identifier (miniUuid or full UUID) Example: abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentExportResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Any | DocumentExportResponse | None: + """Export document (unstable) + + Args: + identifier (str): Document identifier (miniUuid or full UUID) Example: abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentExportResponse + """ + + return sync_detailed( + identifier=identifier, + client=client, + ).parsed + + +async def asyncio_detailed( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | DocumentExportResponse]: + """Export document (unstable) + + Args: + identifier (str): Document identifier (miniUuid or full UUID) Example: abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentExportResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Any | DocumentExportResponse | None: + """Export document (unstable) + + Args: + identifier (str): Document identifier (miniUuid or full UUID) Example: abc123. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentExportResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/unstable/unstable_documents_import.py b/omni_python_sdk/api/unstable/unstable_documents_import.py new file mode 100644 index 0000000..dcf8ff5 --- /dev/null +++ b/omni_python_sdk/api/unstable/unstable_documents_import.py @@ -0,0 +1,177 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.document_import_body import DocumentImportBody +from ...models.document_import_response import DocumentImportResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: DocumentImportBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/unstable/documents/import", + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentImportResponse | None: + if response.status_code == 201: + response_201 = DocumentImportResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentImportResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: DocumentImportBody | Unset = UNSET, +) -> Response[Any | DocumentImportResponse]: + """Import document (unstable) + + Args: + body (DocumentImportBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentImportResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: DocumentImportBody | Unset = UNSET, +) -> Any | DocumentImportResponse | None: + """Import document (unstable) + + Args: + body (DocumentImportBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentImportResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: DocumentImportBody | Unset = UNSET, +) -> Response[Any | DocumentImportResponse]: + """Import document (unstable) + + Args: + body (DocumentImportBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentImportResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: DocumentImportBody | Unset = UNSET, +) -> Any | DocumentImportResponse | None: + """Import document (unstable) + + Args: + body (DocumentImportBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentImportResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/uploads/__init__.py b/omni_python_sdk/api/uploads/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/uploads/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/uploads/uploads_create.py b/omni_python_sdk/api/uploads/uploads_create.py new file mode 100644 index 0000000..7955270 --- /dev/null +++ b/omni_python_sdk/api/uploads/uploads_create.py @@ -0,0 +1,176 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.upload_create_body import UploadCreateBody +from ...models.upload_create_response import UploadCreateResponse +from ...types import Response + + +def _get_kwargs( + *, + body: UploadCreateBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/uploads", + } + + _kwargs["files"] = body.to_multipart() + + headers["Content-Type"] = "multipart/form-data; boundary=+++" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | UploadCreateResponse | None: + if response.status_code == 201: + response_201 = UploadCreateResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | UploadCreateResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: UploadCreateBody, +) -> Response[Any | UploadCreateResponse]: + """Upload CSV file + + Args: + body (UploadCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UploadCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: UploadCreateBody, +) -> Any | UploadCreateResponse | None: + """Upload CSV file + + Args: + body (UploadCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UploadCreateResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: UploadCreateBody, +) -> Response[Any | UploadCreateResponse]: + """Upload CSV file + + Args: + body (UploadCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UploadCreateResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: UploadCreateBody, +) -> Any | UploadCreateResponse | None: + """Upload CSV file + + Args: + body (UploadCreateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UploadCreateResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/uploads/uploads_delete.py b/omni_python_sdk/api/uploads/uploads_delete.py new file mode 100644 index 0000000..7c00052 --- /dev/null +++ b/omni_python_sdk/api/uploads/uploads_delete.py @@ -0,0 +1,172 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.upload_delete_response import UploadDeleteResponse +from ...types import Response + + +def _get_kwargs( + upload_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v1/uploads/{upload_id}".format( + upload_id=quote(str(upload_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | UploadDeleteResponse | None: + if response.status_code == 200: + response_200 = UploadDeleteResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | UploadDeleteResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + upload_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | UploadDeleteResponse]: + """Delete an upload + + Args: + upload_id (UUID): ID of the upload to delete + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UploadDeleteResponse] + """ + + kwargs = _get_kwargs( + upload_id=upload_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + upload_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | UploadDeleteResponse | None: + """Delete an upload + + Args: + upload_id (UUID): ID of the upload to delete + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UploadDeleteResponse + """ + + return sync_detailed( + upload_id=upload_id, + client=client, + ).parsed + + +async def asyncio_detailed( + upload_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | UploadDeleteResponse]: + """Delete an upload + + Args: + upload_id (UUID): ID of the upload to delete + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UploadDeleteResponse] + """ + + kwargs = _get_kwargs( + upload_id=upload_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + upload_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | UploadDeleteResponse | None: + """Delete an upload + + Args: + upload_id (UUID): ID of the upload to delete + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UploadDeleteResponse + """ + + return ( + await asyncio_detailed( + upload_id=upload_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/uploads/uploads_list.py b/omni_python_sdk/api/uploads/uploads_list.py new file mode 100644 index 0000000..f351239 --- /dev/null +++ b/omni_python_sdk/api/uploads/uploads_list.py @@ -0,0 +1,323 @@ +from http import HTTPStatus +from typing import Any, cast +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.uploads_list_response import UploadsListResponse +from ...models.uploads_list_sort_direction import UploadsListSortDirection +from ...models.uploads_list_sort_field import UploadsListSortField +from ...models.uploads_list_type import UploadsListType +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: UploadsListSortDirection | Unset = "desc", + sort_field: UploadsListSortField | Unset = "updatedAt", + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, + search_term: str | Unset = UNSET, + type_: UploadsListType | Unset = "csv", +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["pageSize"] = page_size + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + json_sort_field: str | Unset = UNSET + if not isinstance(sort_field, Unset): + json_sort_field = sort_field + + params["sortField"] = json_sort_field + + json_connection_id: str | Unset = UNSET + if not isinstance(connection_id, Unset): + json_connection_id = str(connection_id) + params["connectionId"] = json_connection_id + + json_model_id: str | Unset = UNSET + if not isinstance(model_id, Unset): + json_model_id = str(model_id) + params["modelId"] = json_model_id + + params["searchTerm"] = search_term + + json_type_: str | Unset = UNSET + if not isinstance(type_, Unset): + json_type_ = type_ + + params["type"] = json_type_ + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/uploads", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | UploadsListResponse | None: + if response.status_code == 200: + response_200 = UploadsListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | UploadsListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: UploadsListSortDirection | Unset = "desc", + sort_field: UploadsListSortField | Unset = "updatedAt", + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, + search_term: str | Unset = UNSET, + type_: UploadsListType | Unset = "csv", +) -> Response[Any | UploadsListResponse]: + """List uploads + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (UploadsListSortDirection | Unset): Sort direction (default: desc) Default: + 'desc'. Example: desc. + sort_field (UploadsListSortField | Unset): Field to sort by (default: updatedAt) Default: + 'updatedAt'. + connection_id (UUID | Unset): Filter by connection ID + model_id (UUID | Unset): Filter by model ID. Shared models return connection uploads; + workbook models return their own uploads. + search_term (str | Unset): Search term to filter by file name + type_ (UploadsListType | Unset): Filter by upload type (default: csv) Default: 'csv'. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UploadsListResponse] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + connection_id=connection_id, + model_id=model_id, + search_term=search_term, + type_=type_, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: UploadsListSortDirection | Unset = "desc", + sort_field: UploadsListSortField | Unset = "updatedAt", + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, + search_term: str | Unset = UNSET, + type_: UploadsListType | Unset = "csv", +) -> Any | UploadsListResponse | None: + """List uploads + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (UploadsListSortDirection | Unset): Sort direction (default: desc) Default: + 'desc'. Example: desc. + sort_field (UploadsListSortField | Unset): Field to sort by (default: updatedAt) Default: + 'updatedAt'. + connection_id (UUID | Unset): Filter by connection ID + model_id (UUID | Unset): Filter by model ID. Shared models return connection uploads; + workbook models return their own uploads. + search_term (str | Unset): Search term to filter by file name + type_ (UploadsListType | Unset): Filter by upload type (default: csv) Default: 'csv'. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UploadsListResponse + """ + + return sync_detailed( + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + connection_id=connection_id, + model_id=model_id, + search_term=search_term, + type_=type_, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: UploadsListSortDirection | Unset = "desc", + sort_field: UploadsListSortField | Unset = "updatedAt", + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, + search_term: str | Unset = UNSET, + type_: UploadsListType | Unset = "csv", +) -> Response[Any | UploadsListResponse]: + """List uploads + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (UploadsListSortDirection | Unset): Sort direction (default: desc) Default: + 'desc'. Example: desc. + sort_field (UploadsListSortField | Unset): Field to sort by (default: updatedAt) Default: + 'updatedAt'. + connection_id (UUID | Unset): Filter by connection ID + model_id (UUID | Unset): Filter by model ID. Shared models return connection uploads; + workbook models return their own uploads. + search_term (str | Unset): Search term to filter by file name + type_ (UploadsListType | Unset): Filter by upload type (default: csv) Default: 'csv'. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UploadsListResponse] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + connection_id=connection_id, + model_id=model_id, + search_term=search_term, + type_=type_, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, + sort_direction: UploadsListSortDirection | Unset = "desc", + sort_field: UploadsListSortField | Unset = "updatedAt", + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, + search_term: str | Unset = UNSET, + type_: UploadsListType | Unset = "csv", +) -> Any | UploadsListResponse | None: + """List uploads + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + sort_direction (UploadsListSortDirection | Unset): Sort direction (default: desc) Default: + 'desc'. Example: desc. + sort_field (UploadsListSortField | Unset): Field to sort by (default: updatedAt) Default: + 'updatedAt'. + connection_id (UUID | Unset): Filter by connection ID + model_id (UUID | Unset): Filter by model ID. Shared models return connection uploads; + workbook models return their own uploads. + search_term (str | Unset): Search term to filter by file name + type_ (UploadsListType | Unset): Filter by upload type (default: csv) Default: 'csv'. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UploadsListResponse + """ + + return ( + await asyncio_detailed( + client=client, + cursor=cursor, + page_size=page_size, + sort_direction=sort_direction, + sort_field=sort_field, + connection_id=connection_id, + model_id=model_id, + search_term=search_term, + type_=type_, + ) + ).parsed diff --git a/omni_python_sdk/api/user_attributes/__init__.py b/omni_python_sdk/api/user_attributes/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/user_attributes/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/user_attributes/user_attributes_list.py b/omni_python_sdk/api/user_attributes/user_attributes_list.py new file mode 100644 index 0000000..ef435d1 --- /dev/null +++ b/omni_python_sdk/api/user_attributes/user_attributes_list.py @@ -0,0 +1,148 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.user_attributes_list_response import UserAttributesListResponse +from ...types import Response + + +def _get_kwargs() -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/user-attributes", + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | UserAttributesListResponse | None: + if response.status_code == 200: + response_200 = UserAttributesListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | UserAttributesListResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, +) -> Response[Any | UserAttributesListResponse]: + """List all user attribute definitions + + Returns all user attribute definitions in the organization, including system-defined attributes + (e.g. omni_user_id, omni_user_email) and custom attributes. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UserAttributesListResponse] + """ + + kwargs = _get_kwargs() + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, +) -> Any | UserAttributesListResponse | None: + """List all user attribute definitions + + Returns all user attribute definitions in the organization, including system-defined attributes + (e.g. omni_user_id, omni_user_email) and custom attributes. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UserAttributesListResponse + """ + + return sync_detailed( + client=client, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, +) -> Response[Any | UserAttributesListResponse]: + """List all user attribute definitions + + Returns all user attribute definitions in the organization, including system-defined attributes + (e.g. omni_user_id, omni_user_email) and custom attributes. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UserAttributesListResponse] + """ + + kwargs = _get_kwargs() + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, +) -> Any | UserAttributesListResponse | None: + """List all user attribute definitions + + Returns all user attribute definitions in the organization, including system-defined attributes + (e.g. omni_user_id, omni_user_email) and custom attributes. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UserAttributesListResponse + """ + + return ( + await asyncio_detailed( + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/users/__init__.py b/omni_python_sdk/api/users/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/users/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/users/user_groups_assign_model_role.py b/omni_python_sdk/api/users/user_groups_assign_model_role.py new file mode 100644 index 0000000..bda3d77 --- /dev/null +++ b/omni_python_sdk/api/users/user_groups_assign_model_role.py @@ -0,0 +1,193 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.user_groups_assign_model_role_body import UserGroupsAssignModelRoleBody +from ...models.user_groups_assign_model_role_response import UserGroupsAssignModelRoleResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: str, + *, + body: UserGroupsAssignModelRoleBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/user-groups/{id}/model-roles".format( + id=quote(str(id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | UserGroupsAssignModelRoleResponse | None: + if response.status_code == 200: + response_200 = UserGroupsAssignModelRoleResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | UserGroupsAssignModelRoleResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: str, + *, + client: AuthenticatedClient | Client, + body: UserGroupsAssignModelRoleBody | Unset = UNSET, +) -> Response[Any | UserGroupsAssignModelRoleResponse]: + """Assign model role to user group + + Args: + id (str): User group short identifier (miniUuid) Example: abc123. + body (UserGroupsAssignModelRoleBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UserGroupsAssignModelRoleResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: str, + *, + client: AuthenticatedClient | Client, + body: UserGroupsAssignModelRoleBody | Unset = UNSET, +) -> Any | UserGroupsAssignModelRoleResponse | None: + """Assign model role to user group + + Args: + id (str): User group short identifier (miniUuid) Example: abc123. + body (UserGroupsAssignModelRoleBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UserGroupsAssignModelRoleResponse + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: str, + *, + client: AuthenticatedClient | Client, + body: UserGroupsAssignModelRoleBody | Unset = UNSET, +) -> Response[Any | UserGroupsAssignModelRoleResponse]: + """Assign model role to user group + + Args: + id (str): User group short identifier (miniUuid) Example: abc123. + body (UserGroupsAssignModelRoleBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UserGroupsAssignModelRoleResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: str, + *, + client: AuthenticatedClient | Client, + body: UserGroupsAssignModelRoleBody | Unset = UNSET, +) -> Any | UserGroupsAssignModelRoleResponse | None: + """Assign model role to user group + + Args: + id (str): User group short identifier (miniUuid) Example: abc123. + body (UserGroupsAssignModelRoleBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UserGroupsAssignModelRoleResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/users/user_groups_get_model_roles.py b/omni_python_sdk/api/users/user_groups_get_model_roles.py new file mode 100644 index 0000000..c75d99c --- /dev/null +++ b/omni_python_sdk/api/users/user_groups_get_model_roles.py @@ -0,0 +1,218 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.user_groups_get_model_roles_response import UserGroupsGetModelRolesResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: str, + *, + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_connection_id: str | Unset = UNSET + if not isinstance(connection_id, Unset): + json_connection_id = str(connection_id) + params["connectionId"] = json_connection_id + + json_model_id: str | Unset = UNSET + if not isinstance(model_id, Unset): + json_model_id = str(model_id) + params["modelId"] = json_model_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/user-groups/{id}/model-roles".format( + id=quote(str(id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | UserGroupsGetModelRolesResponse | None: + if response.status_code == 200: + response_200 = UserGroupsGetModelRolesResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | UserGroupsGetModelRolesResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: str, + *, + client: AuthenticatedClient | Client, + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, +) -> Response[Any | UserGroupsGetModelRolesResponse]: + """Get user group model roles + + Args: + id (str): User group short identifier (miniUuid) Example: abc123. + connection_id (UUID | Unset): Filter results to a specific connection Example: + 550e8400-e29b-41d4-a716-446655440000. + model_id (UUID | Unset): Filter results to a specific model Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UserGroupsGetModelRolesResponse] + """ + + kwargs = _get_kwargs( + id=id, + connection_id=connection_id, + model_id=model_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: str, + *, + client: AuthenticatedClient | Client, + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, +) -> Any | UserGroupsGetModelRolesResponse | None: + """Get user group model roles + + Args: + id (str): User group short identifier (miniUuid) Example: abc123. + connection_id (UUID | Unset): Filter results to a specific connection Example: + 550e8400-e29b-41d4-a716-446655440000. + model_id (UUID | Unset): Filter results to a specific model Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UserGroupsGetModelRolesResponse + """ + + return sync_detailed( + id=id, + client=client, + connection_id=connection_id, + model_id=model_id, + ).parsed + + +async def asyncio_detailed( + id: str, + *, + client: AuthenticatedClient | Client, + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, +) -> Response[Any | UserGroupsGetModelRolesResponse]: + """Get user group model roles + + Args: + id (str): User group short identifier (miniUuid) Example: abc123. + connection_id (UUID | Unset): Filter results to a specific connection Example: + 550e8400-e29b-41d4-a716-446655440000. + model_id (UUID | Unset): Filter results to a specific model Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UserGroupsGetModelRolesResponse] + """ + + kwargs = _get_kwargs( + id=id, + connection_id=connection_id, + model_id=model_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: str, + *, + client: AuthenticatedClient | Client, + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, +) -> Any | UserGroupsGetModelRolesResponse | None: + """Get user group model roles + + Args: + id (str): User group short identifier (miniUuid) Example: abc123. + connection_id (UUID | Unset): Filter results to a specific connection Example: + 550e8400-e29b-41d4-a716-446655440000. + model_id (UUID | Unset): Filter results to a specific model Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UserGroupsGetModelRolesResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + connection_id=connection_id, + model_id=model_id, + ) + ).parsed diff --git a/omni_python_sdk/api/users/users_assign_model_role.py b/omni_python_sdk/api/users/users_assign_model_role.py new file mode 100644 index 0000000..e073809 --- /dev/null +++ b/omni_python_sdk/api/users/users_assign_model_role.py @@ -0,0 +1,194 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.users_assign_model_role_body import UsersAssignModelRoleBody +from ...models.users_assign_model_role_response import UsersAssignModelRoleResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: UUID, + *, + body: UsersAssignModelRoleBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/users/{id}/model-roles".format( + id=quote(str(id), safe=""), + ), + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | UsersAssignModelRoleResponse | None: + if response.status_code == 200: + response_200 = UsersAssignModelRoleResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | UsersAssignModelRoleResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: UsersAssignModelRoleBody | Unset = UNSET, +) -> Response[Any | UsersAssignModelRoleResponse]: + """Assign model role to user + + Args: + id (UUID): User membership ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (UsersAssignModelRoleBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UsersAssignModelRoleResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: UsersAssignModelRoleBody | Unset = UNSET, +) -> Any | UsersAssignModelRoleResponse | None: + """Assign model role to user + + Args: + id (UUID): User membership ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (UsersAssignModelRoleBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UsersAssignModelRoleResponse + """ + + return sync_detailed( + id=id, + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: UsersAssignModelRoleBody | Unset = UNSET, +) -> Response[Any | UsersAssignModelRoleResponse]: + """Assign model role to user + + Args: + id (UUID): User membership ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (UsersAssignModelRoleBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UsersAssignModelRoleResponse] + """ + + kwargs = _get_kwargs( + id=id, + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, + body: UsersAssignModelRoleBody | Unset = UNSET, +) -> Any | UsersAssignModelRoleResponse | None: + """Assign model role to user + + Args: + id (UUID): User membership ID Example: 550e8400-e29b-41d4-a716-446655440000. + body (UsersAssignModelRoleBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UsersAssignModelRoleResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/users/users_create_email_only.py b/omni_python_sdk/api/users/users_create_email_only.py new file mode 100644 index 0000000..2064ee9 --- /dev/null +++ b/omni_python_sdk/api/users/users_create_email_only.py @@ -0,0 +1,173 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.users_create_email_only_body import UsersCreateEmailOnlyBody +from ...models.users_create_email_only_response import UsersCreateEmailOnlyResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: UsersCreateEmailOnlyBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/users/email-only", + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | UsersCreateEmailOnlyResponse | None: + if response.status_code == 200: + response_200 = UsersCreateEmailOnlyResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | UsersCreateEmailOnlyResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: UsersCreateEmailOnlyBody | Unset = UNSET, +) -> Response[Any | UsersCreateEmailOnlyResponse]: + """Create or update email-only user + + Args: + body (UsersCreateEmailOnlyBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UsersCreateEmailOnlyResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: UsersCreateEmailOnlyBody | Unset = UNSET, +) -> Any | UsersCreateEmailOnlyResponse | None: + """Create or update email-only user + + Args: + body (UsersCreateEmailOnlyBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UsersCreateEmailOnlyResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: UsersCreateEmailOnlyBody | Unset = UNSET, +) -> Response[Any | UsersCreateEmailOnlyResponse]: + """Create or update email-only user + + Args: + body (UsersCreateEmailOnlyBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UsersCreateEmailOnlyResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: UsersCreateEmailOnlyBody | Unset = UNSET, +) -> Any | UsersCreateEmailOnlyResponse | None: + """Create or update email-only user + + Args: + body (UsersCreateEmailOnlyBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UsersCreateEmailOnlyResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/users/users_create_email_only_bulk.py b/omni_python_sdk/api/users/users_create_email_only_bulk.py new file mode 100644 index 0000000..f074478 --- /dev/null +++ b/omni_python_sdk/api/users/users_create_email_only_bulk.py @@ -0,0 +1,173 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.users_create_email_only_bulk_body import UsersCreateEmailOnlyBulkBody +from ...models.users_create_email_only_bulk_response import UsersCreateEmailOnlyBulkResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + body: UsersCreateEmailOnlyBulkBody | Unset = UNSET, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/users/email-only/bulk", + } + + if not isinstance(body, Unset): + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | UsersCreateEmailOnlyBulkResponse | None: + if response.status_code == 201: + response_201 = UsersCreateEmailOnlyBulkResponse.from_dict(response.json()) + + return response_201 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | UsersCreateEmailOnlyBulkResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: UsersCreateEmailOnlyBulkBody | Unset = UNSET, +) -> Response[Any | UsersCreateEmailOnlyBulkResponse]: + """Create email-only users in bulk + + Args: + body (UsersCreateEmailOnlyBulkBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UsersCreateEmailOnlyBulkResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: UsersCreateEmailOnlyBulkBody | Unset = UNSET, +) -> Any | UsersCreateEmailOnlyBulkResponse | None: + """Create email-only users in bulk + + Args: + body (UsersCreateEmailOnlyBulkBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UsersCreateEmailOnlyBulkResponse + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: UsersCreateEmailOnlyBulkBody | Unset = UNSET, +) -> Response[Any | UsersCreateEmailOnlyBulkResponse]: + """Create email-only users in bulk + + Args: + body (UsersCreateEmailOnlyBulkBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UsersCreateEmailOnlyBulkResponse] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: UsersCreateEmailOnlyBulkBody | Unset = UNSET, +) -> Any | UsersCreateEmailOnlyBulkResponse | None: + """Create email-only users in bulk + + Args: + body (UsersCreateEmailOnlyBulkBody | Unset): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UsersCreateEmailOnlyBulkResponse + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/users/users_get_model_roles.py b/omni_python_sdk/api/users/users_get_model_roles.py new file mode 100644 index 0000000..c2bd2d4 --- /dev/null +++ b/omni_python_sdk/api/users/users_get_model_roles.py @@ -0,0 +1,218 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.users_get_model_roles_response import UsersGetModelRolesResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + id: UUID, + *, + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + json_connection_id: str | Unset = UNSET + if not isinstance(connection_id, Unset): + json_connection_id = str(connection_id) + params["connectionId"] = json_connection_id + + json_model_id: str | Unset = UNSET + if not isinstance(model_id, Unset): + json_model_id = str(model_id) + params["modelId"] = json_model_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/users/{id}/model-roles".format( + id=quote(str(id), safe=""), + ), + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | UsersGetModelRolesResponse | None: + if response.status_code == 200: + response_200 = UsersGetModelRolesResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | UsersGetModelRolesResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, +) -> Response[Any | UsersGetModelRolesResponse]: + """Get user model roles + + Args: + id (UUID): User membership ID Example: 550e8400-e29b-41d4-a716-446655440000. + connection_id (UUID | Unset): Filter results to a specific connection Example: + 550e8400-e29b-41d4-a716-446655440000. + model_id (UUID | Unset): Filter results to a specific model Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UsersGetModelRolesResponse] + """ + + kwargs = _get_kwargs( + id=id, + connection_id=connection_id, + model_id=model_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + id: UUID, + *, + client: AuthenticatedClient | Client, + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, +) -> Any | UsersGetModelRolesResponse | None: + """Get user model roles + + Args: + id (UUID): User membership ID Example: 550e8400-e29b-41d4-a716-446655440000. + connection_id (UUID | Unset): Filter results to a specific connection Example: + 550e8400-e29b-41d4-a716-446655440000. + model_id (UUID | Unset): Filter results to a specific model Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UsersGetModelRolesResponse + """ + + return sync_detailed( + id=id, + client=client, + connection_id=connection_id, + model_id=model_id, + ).parsed + + +async def asyncio_detailed( + id: UUID, + *, + client: AuthenticatedClient | Client, + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, +) -> Response[Any | UsersGetModelRolesResponse]: + """Get user model roles + + Args: + id (UUID): User membership ID Example: 550e8400-e29b-41d4-a716-446655440000. + connection_id (UUID | Unset): Filter results to a specific connection Example: + 550e8400-e29b-41d4-a716-446655440000. + model_id (UUID | Unset): Filter results to a specific model Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UsersGetModelRolesResponse] + """ + + kwargs = _get_kwargs( + id=id, + connection_id=connection_id, + model_id=model_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + id: UUID, + *, + client: AuthenticatedClient | Client, + connection_id: UUID | Unset = UNSET, + model_id: UUID | Unset = UNSET, +) -> Any | UsersGetModelRolesResponse | None: + """Get user model roles + + Args: + id (UUID): User membership ID Example: 550e8400-e29b-41d4-a716-446655440000. + connection_id (UUID | Unset): Filter results to a specific connection Example: + 550e8400-e29b-41d4-a716-446655440000. + model_id (UUID | Unset): Filter results to a specific model Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UsersGetModelRolesResponse + """ + + return ( + await asyncio_detailed( + id=id, + client=client, + connection_id=connection_id, + model_id=model_id, + ) + ).parsed diff --git a/omni_python_sdk/api/users/users_list_email_only.py b/omni_python_sdk/api/users/users_list_email_only.py new file mode 100644 index 0000000..161c28f --- /dev/null +++ b/omni_python_sdk/api/users/users_list_email_only.py @@ -0,0 +1,224 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.users_list_email_only_response import UsersListEmailOnlyResponse +from ...models.users_list_email_only_sort_direction import ( + UsersListEmailOnlySortDirection, +) +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + cursor: str | Unset = UNSET, + email: str | Unset = UNSET, + page_size: float | Unset = 20.0, + sort_direction: UsersListEmailOnlySortDirection | Unset = "desc", +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["email"] = email + + params["pageSize"] = page_size + + json_sort_direction: str | Unset = UNSET + if not isinstance(sort_direction, Unset): + json_sort_direction = sort_direction + + params["sortDirection"] = json_sort_direction + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/users/email-only", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | UsersListEmailOnlyResponse | None: + if response.status_code == 200: + response_200 = UsersListEmailOnlyResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | UsersListEmailOnlyResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + email: str | Unset = UNSET, + page_size: float | Unset = 20.0, + sort_direction: UsersListEmailOnlySortDirection | Unset = "desc", +) -> Response[Any | UsersListEmailOnlyResponse]: + """List email-only users + + Args: + cursor (str | Unset): Cursor for pagination + email (str | Unset): Filter by email address Example: user@example.com. + page_size (float | Unset): Number of results per page (max 20) Default: 20.0. Example: 20. + sort_direction (UsersListEmailOnlySortDirection | Unset): Sort direction for results + Default: 'desc'. Example: desc. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UsersListEmailOnlyResponse] + """ + + kwargs = _get_kwargs( + cursor=cursor, + email=email, + page_size=page_size, + sort_direction=sort_direction, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + email: str | Unset = UNSET, + page_size: float | Unset = 20.0, + sort_direction: UsersListEmailOnlySortDirection | Unset = "desc", +) -> Any | UsersListEmailOnlyResponse | None: + """List email-only users + + Args: + cursor (str | Unset): Cursor for pagination + email (str | Unset): Filter by email address Example: user@example.com. + page_size (float | Unset): Number of results per page (max 20) Default: 20.0. Example: 20. + sort_direction (UsersListEmailOnlySortDirection | Unset): Sort direction for results + Default: 'desc'. Example: desc. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UsersListEmailOnlyResponse + """ + + return sync_detailed( + client=client, + cursor=cursor, + email=email, + page_size=page_size, + sort_direction=sort_direction, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + email: str | Unset = UNSET, + page_size: float | Unset = 20.0, + sort_direction: UsersListEmailOnlySortDirection | Unset = "desc", +) -> Response[Any | UsersListEmailOnlyResponse]: + """List email-only users + + Args: + cursor (str | Unset): Cursor for pagination + email (str | Unset): Filter by email address Example: user@example.com. + page_size (float | Unset): Number of results per page (max 20) Default: 20.0. Example: 20. + sort_direction (UsersListEmailOnlySortDirection | Unset): Sort direction for results + Default: 'desc'. Example: desc. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | UsersListEmailOnlyResponse] + """ + + kwargs = _get_kwargs( + cursor=cursor, + email=email, + page_size=page_size, + sort_direction=sort_direction, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + email: str | Unset = UNSET, + page_size: float | Unset = 20.0, + sort_direction: UsersListEmailOnlySortDirection | Unset = "desc", +) -> Any | UsersListEmailOnlyResponse | None: + """List email-only users + + Args: + cursor (str | Unset): Cursor for pagination + email (str | Unset): Filter by email address Example: user@example.com. + page_size (float | Unset): Number of results per page (max 20) Default: 20.0. Example: 20. + sort_direction (UsersListEmailOnlySortDirection | Unset): Sort direction for results + Default: 'desc'. Example: desc. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | UsersListEmailOnlyResponse + """ + + return ( + await asyncio_detailed( + client=client, + cursor=cursor, + email=email, + page_size=page_size, + sort_direction=sort_direction, + ) + ).parsed diff --git a/omni_python_sdk/api/whoami/__init__.py b/omni_python_sdk/api/whoami/__init__.py new file mode 100644 index 0000000..2d7c0b2 --- /dev/null +++ b/omni_python_sdk/api/whoami/__init__.py @@ -0,0 +1 @@ +"""Contains endpoint functions for accessing the API""" diff --git a/omni_python_sdk/api/whoami/whoami.py b/omni_python_sdk/api/whoami/whoami.py new file mode 100644 index 0000000..97e99ac --- /dev/null +++ b/omni_python_sdk/api/whoami/whoami.py @@ -0,0 +1,198 @@ +from http import HTTPStatus +from typing import Any, cast + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.whoami_response import WhoamiResponse +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + model_id: str | Unset = UNSET, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["modelId"] = model_id + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/whoami", + "params": params, + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | WhoamiResponse | None: + if response.status_code == 200: + response_200 = WhoamiResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | WhoamiResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + model_id: str | Unset = UNSET, +) -> Response[Any | WhoamiResponse]: + """Get current identity and permissions (whoami) + + Returns the authenticated caller's own identity, API key scope, organization role, and resolved per- + model permissions. Self-scoped and available to non-admins: it lets a caller decide whether an + action is permitted without attempting it. Pass `modelId` to scope `rolesByModel` to specific + models. + + Args: + model_id (str | Unset): Optional model filter. A single model id or a comma-separated + list. When provided, `rolesByModel` contains only these models. When omitted, models the + caller can access are returned (up to a limit; see `rolesByModelTruncated`). Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | WhoamiResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + model_id: str | Unset = UNSET, +) -> Any | WhoamiResponse | None: + """Get current identity and permissions (whoami) + + Returns the authenticated caller's own identity, API key scope, organization role, and resolved per- + model permissions. Self-scoped and available to non-admins: it lets a caller decide whether an + action is permitted without attempting it. Pass `modelId` to scope `rolesByModel` to specific + models. + + Args: + model_id (str | Unset): Optional model filter. A single model id or a comma-separated + list. When provided, `rolesByModel` contains only these models. When omitted, models the + caller can access are returned (up to a limit; see `rolesByModelTruncated`). Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | WhoamiResponse + """ + + return sync_detailed( + client=client, + model_id=model_id, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + model_id: str | Unset = UNSET, +) -> Response[Any | WhoamiResponse]: + """Get current identity and permissions (whoami) + + Returns the authenticated caller's own identity, API key scope, organization role, and resolved per- + model permissions. Self-scoped and available to non-admins: it lets a caller decide whether an + action is permitted without attempting it. Pass `modelId` to scope `rolesByModel` to specific + models. + + Args: + model_id (str | Unset): Optional model filter. A single model id or a comma-separated + list. When provided, `rolesByModel` contains only these models. When omitted, models the + caller can access are returned (up to a limit; see `rolesByModelTruncated`). Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | WhoamiResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + model_id: str | Unset = UNSET, +) -> Any | WhoamiResponse | None: + """Get current identity and permissions (whoami) + + Returns the authenticated caller's own identity, API key scope, organization role, and resolved per- + model permissions. Self-scoped and available to non-admins: it lets a caller decide whether an + action is permitted without attempting it. Pass `modelId` to scope `rolesByModel` to specific + models. + + Args: + model_id (str | Unset): Optional model filter. A single model id or a comma-separated + list. When provided, `rolesByModel` contains only these models. When omitted, models the + caller can access are returned (up to a limit; see `rolesByModelTruncated`). Example: + 550e8400-e29b-41d4-a716-446655440000. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | WhoamiResponse + """ + + return ( + await asyncio_detailed( + client=client, + model_id=model_id, + ) + ).parsed diff --git a/omni_python_sdk/client.py b/omni_python_sdk/client.py new file mode 100644 index 0000000..1b7055a --- /dev/null +++ b/omni_python_sdk/client.py @@ -0,0 +1,268 @@ +import ssl +from typing import Any + +import httpx +from attrs import define, evolve, field + + +@define +class Client: + """A class for keeping track of data related to the API + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: httpx.Timeout | None = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: str | bool | ssl.SSLContext = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: httpx.Client | None = field(default=None, init=False) + _async_client: httpx.AsyncClient | None = field(default=None, init=False) + + def with_headers(self, headers: dict[str, str]) -> "Client": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "Client": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "Client": + """Get a new client matching this one with a new timeout configuration""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "Client": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "Client": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "Client": + """Manually set the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "Client": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) + + +@define +class AuthenticatedClient: + """A Client which has been authenticated for use on secured endpoints + + The following are accepted as keyword arguments and will be used to construct httpx Clients internally: + + ``base_url``: The base URL for the API, all requests are made to a relative path to this URL + + ``cookies``: A dictionary of cookies to be sent with every request + + ``headers``: A dictionary of headers to be sent with every request + + ``timeout``: The maximum amount of a time a request can take. API functions will raise + httpx.TimeoutException if this is exceeded. + + ``verify_ssl``: Whether or not to verify the SSL certificate of the API server. This should be True in production, + but can be set to False for testing purposes. + + ``follow_redirects``: Whether or not to follow redirects. Default value is False. + + ``httpx_args``: A dictionary of additional arguments to be passed to the ``httpx.Client`` and ``httpx.AsyncClient`` constructor. + + + Attributes: + raise_on_unexpected_status: Whether or not to raise an errors.UnexpectedStatus if the API returns a + status code that was not documented in the source OpenAPI document. Can also be provided as a keyword + argument to the constructor. + token: The token to use for authentication + prefix: The prefix to use for the Authorization header + auth_header_name: The name of the Authorization header + """ + + raise_on_unexpected_status: bool = field(default=False, kw_only=True) + _base_url: str = field(alias="base_url") + _cookies: dict[str, str] = field(factory=dict, kw_only=True, alias="cookies") + _headers: dict[str, str] = field(factory=dict, kw_only=True, alias="headers") + _timeout: httpx.Timeout | None = field(default=None, kw_only=True, alias="timeout") + _verify_ssl: str | bool | ssl.SSLContext = field(default=True, kw_only=True, alias="verify_ssl") + _follow_redirects: bool = field(default=False, kw_only=True, alias="follow_redirects") + _httpx_args: dict[str, Any] = field(factory=dict, kw_only=True, alias="httpx_args") + _client: httpx.Client | None = field(default=None, init=False) + _async_client: httpx.AsyncClient | None = field(default=None, init=False) + + token: str + prefix: str = "Bearer" + auth_header_name: str = "Authorization" + + def with_headers(self, headers: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional headers""" + if self._client is not None: + self._client.headers.update(headers) + if self._async_client is not None: + self._async_client.headers.update(headers) + return evolve(self, headers={**self._headers, **headers}) + + def with_cookies(self, cookies: dict[str, str]) -> "AuthenticatedClient": + """Get a new client matching this one with additional cookies""" + if self._client is not None: + self._client.cookies.update(cookies) + if self._async_client is not None: + self._async_client.cookies.update(cookies) + return evolve(self, cookies={**self._cookies, **cookies}) + + def with_timeout(self, timeout: httpx.Timeout) -> "AuthenticatedClient": + """Get a new client matching this one with a new timeout configuration""" + if self._client is not None: + self._client.timeout = timeout + if self._async_client is not None: + self._async_client.timeout = timeout + return evolve(self, timeout=timeout) + + def set_httpx_client(self, client: httpx.Client) -> "AuthenticatedClient": + """Manually set the underlying httpx.Client + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._client = client + return self + + def get_httpx_client(self) -> httpx.Client: + """Get the underlying httpx.Client, constructing a new one if not previously set""" + if self._client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._client = httpx.Client( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._client + + def __enter__(self) -> "AuthenticatedClient": + """Enter a context manager for self.client—you cannot enter twice (see httpx docs)""" + self.get_httpx_client().__enter__() + return self + + def __exit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for internal httpx.Client (see httpx docs)""" + self.get_httpx_client().__exit__(*args, **kwargs) + + def set_async_httpx_client(self, async_client: httpx.AsyncClient) -> "AuthenticatedClient": + """Manually set the underlying httpx.AsyncClient + + **NOTE**: This will override any other settings on the client, including cookies, headers, and timeout. + """ + self._async_client = async_client + return self + + def get_async_httpx_client(self) -> httpx.AsyncClient: + """Get the underlying httpx.AsyncClient, constructing a new one if not previously set""" + if self._async_client is None: + self._headers[self.auth_header_name] = f"{self.prefix} {self.token}" if self.prefix else self.token + self._async_client = httpx.AsyncClient( + base_url=self._base_url, + cookies=self._cookies, + headers=self._headers, + timeout=self._timeout, + verify=self._verify_ssl, + follow_redirects=self._follow_redirects, + **self._httpx_args, + ) + return self._async_client + + async def __aenter__(self) -> "AuthenticatedClient": + """Enter a context manager for underlying httpx.AsyncClient—you cannot enter twice (see httpx docs)""" + await self.get_async_httpx_client().__aenter__() + return self + + async def __aexit__(self, *args: Any, **kwargs: Any) -> None: + """Exit a context manager for underlying httpx.AsyncClient (see httpx docs)""" + await self.get_async_httpx_client().__aexit__(*args, **kwargs) diff --git a/omni_python_sdk/errors.py b/omni_python_sdk/errors.py new file mode 100644 index 0000000..5f92e76 --- /dev/null +++ b/omni_python_sdk/errors.py @@ -0,0 +1,16 @@ +"""Contains shared errors types that can be raised from API functions""" + + +class UnexpectedStatus(Exception): + """Raised by api functions when the response status an undocumented status and Client.raise_on_unexpected_status is True""" + + def __init__(self, status_code: int, content: bytes): + self.status_code = status_code + self.content = content + + super().__init__( + f"Unexpected status code: {status_code}\n\nResponse content:\n{content.decode(errors='ignore')}" + ) + + +__all__ = ["UnexpectedStatus"] diff --git a/omni_python_sdk/models/__init__.py b/omni_python_sdk/models/__init__.py new file mode 100644 index 0000000..664aeeb --- /dev/null +++ b/omni_python_sdk/models/__init__.py @@ -0,0 +1,1263 @@ +"""Contains all the data models used in inputs/outputs""" + +from .ai_agent_action import AiAgentAction +from .ai_agent_action_kind import AiAgentActionKind +from .ai_agent_actions_response import AiAgentActionsResponse +from .ai_branding_response import AiBrandingResponse +from .ai_conversation import AiConversation +from .ai_conversation_detail_response import AiConversationDetailResponse +from .ai_conversation_message import AiConversationMessage +from .ai_conversation_message_role import AiConversationMessageRole +from .ai_conversations_list_response import AiConversationsListResponse +from .ai_credit_controls_response import AiCreditControlsResponse +from .ai_credit_controls_update_body import AiCreditControlsUpdateBody +from .ai_credit_controls_users_list_response import AiCreditControlsUsersListResponse +from .ai_credit_controls_users_list_response_records_item import AiCreditControlsUsersListResponseRecordsItem +from .ai_credit_shutoff_error import AiCreditShutoffError +from .ai_credit_shutoff_error_code import AiCreditShutoffErrorCode +from .ai_eval_prompt_sets_list_archived import AiEvalPromptSetsListArchived +from .ai_eval_runs_list_archived import AiEvalRunsListArchived +from .ai_generate_query_body import AiGenerateQueryBody +from .ai_generate_query_response import AiGenerateQueryResponse +from .ai_generate_query_response_error_type_0 import AiGenerateQueryResponseErrorType0 +from .ai_generate_query_response_result import AiGenerateQueryResponseResult +from .ai_job_action import AiJobAction +from .ai_job_action_query_result import AiJobActionQueryResult +from .ai_job_action_query_result_query import AiJobActionQueryResultQuery +from .ai_job_action_query_result_status import AiJobActionQueryResultStatus +from .ai_job_cancel_response import AiJobCancelResponse +from .ai_job_cancel_response_state import AiJobCancelResponseState +from .ai_job_result_response import AiJobResultResponse +from .ai_job_status_response import AiJobStatusResponse +from .ai_job_status_response_error import AiJobStatusResponseError +from .ai_job_status_response_progress_type_0 import AiJobStatusResponseProgressType0 +from .ai_job_status_response_state import AiJobStatusResponseState +from .ai_job_submit_body import AiJobSubmitBody +from .ai_job_submit_body_webhook_metadata import AiJobSubmitBodyWebhookMetadata +from .ai_job_submit_response import AiJobSubmitResponse +from .ai_pick_topic_body import AiPickTopicBody +from .ai_pick_topic_response import AiPickTopicResponse +from .ai_query_sort import AiQuerySort +from .ai_search_omni_docs_body import AiSearchOmniDocsBody +from .ai_search_omni_docs_response import AiSearchOmniDocsResponse +from .ai_search_omni_docs_response_sources_item import AiSearchOmniDocsResponseSourcesItem +from .ai_semantic_query import AiSemanticQuery +from .ai_topic_params import AiTopicParams +from .ai_user_credit_limit_entry import AiUserCreditLimitEntry +from .ai_user_credit_limits_response import AiUserCreditLimitsResponse +from .ai_user_credit_limits_response_users_item import AiUserCreditLimitsResponseUsersItem +from .ai_user_credit_limits_update_body import AiUserCreditLimitsUpdateBody +from .api_document import ApiDocument +from .api_document_count import ApiDocumentCount +from .api_draft import ApiDraft +from .api_draft_actor import ApiDraftActor +from .api_draft_branch_type_0 import ApiDraftBranchType0 +from .api_draft_status import ApiDraftStatus +from .api_error_400 import ApiError400 +from .api_error_401 import ApiError401 +from .api_error_403 import ApiError403 +from .api_error_404 import ApiError404 +from .api_error_409 import ApiError409 +from .api_error_422 import ApiError422 +from .api_error_429 import ApiError429 +from .api_key import ApiKey +from .api_key_delete_response import ApiKeyDeleteResponse +from .api_key_list_response import ApiKeyListResponse +from .api_key_type import ApiKeyType +from .api_key_update_body import ApiKeyUpdateBody +from .api_keys_list_sort_direction import ApiKeysListSortDirection +from .api_keys_list_sort_field import ApiKeysListSortField +from .api_keys_list_type import ApiKeysListType +from .api_vis_config import ApiVisConfig +from .composite_filter import CompositeFilter +from .composite_filter_conjunction import CompositeFilterConjunction +from .composite_filter_filters_item_type_0 import CompositeFilterFiltersItemType0 +from .composite_filter_filters_item_type_0_applied_labels import CompositeFilterFiltersItemType0AppliedLabels +from .composite_filter_filters_item_type_0_kind import CompositeFilterFiltersItemType0Kind +from .composite_filter_filters_item_type_0_type import CompositeFilterFiltersItemType0Type +from .composite_filter_filters_item_type_1 import CompositeFilterFiltersItemType1 +from .composite_filter_filters_item_type_1_kind import CompositeFilterFiltersItemType1Kind +from .composite_filter_filters_item_type_1_type import CompositeFilterFiltersItemType1Type +from .composite_filter_filters_item_type_2 import CompositeFilterFiltersItemType2 +from .composite_filter_filters_item_type_2_kind import CompositeFilterFiltersItemType2Kind +from .composite_filter_filters_item_type_2_type import CompositeFilterFiltersItemType2Type +from .composite_filter_filters_item_type_2_ui_type_type_1 import CompositeFilterFiltersItemType2UiTypeType1 +from .composite_filter_filters_item_type_2_ui_type_type_2_type_1 import CompositeFilterFiltersItemType2UiTypeType2Type1 +from .composite_filter_filters_item_type_2_ui_type_type_3_type_1 import CompositeFilterFiltersItemType2UiTypeType3Type1 +from .composite_filter_filters_item_type_3 import CompositeFilterFiltersItemType3 +from .composite_filter_filters_item_type_3_type import CompositeFilterFiltersItemType3Type +from .composite_filter_filters_item_type_4 import CompositeFilterFiltersItemType4 +from .composite_filter_filters_item_type_4_type import CompositeFilterFiltersItemType4Type +from .composite_filter_filters_item_type_5 import CompositeFilterFiltersItemType5 +from .composite_filter_filters_item_type_5_type import CompositeFilterFiltersItemType5Type +from .composite_filter_filters_item_type_5_view_query import CompositeFilterFiltersItemType5ViewQuery +from .composite_filter_filters_item_type_5_view_query_filters import CompositeFilterFiltersItemType5ViewQueryFilters +from .composite_filter_filters_item_type_6 import CompositeFilterFiltersItemType6 +from .composite_filter_filters_item_type_6_type import CompositeFilterFiltersItemType6Type +from .composite_filter_type import CompositeFilterType +from .connection_environments_create_connections_environments_create_body import ( + ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody, +) +from .connection_environments_create_connections_environments_create_response import ( + ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse, +) +from .connection_environments_create_connections_environments_create_response_connection_environment import ( + ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponseConnectionEnvironment, +) +from .connection_environments_delete_connections_environments_delete_response import ( + ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse, +) +from .connection_environments_update_connections_environments_update_body import ( + ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody, +) +from .connection_environments_update_connections_environments_update_response import ( + ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse, +) +from .connections_create_connections_create_body import ConnectionsCreateConnectionsCreateBody +from .connections_create_connections_create_body_base_role import ConnectionsCreateConnectionsCreateBodyBaseRole +from .connections_create_connections_create_body_dialect import ConnectionsCreateConnectionsCreateBodyDialect +from .connections_create_connections_create_response import ConnectionsCreateConnectionsCreateResponse +from .connections_dbt_delete_connections_dbt_delete_response import ConnectionsDbtDeleteConnectionsDbtDeleteResponse +from .connections_dbt_environments_list_sort_direction import ConnectionsDbtEnvironmentsListSortDirection +from .connections_dbt_environments_list_sort_field import ConnectionsDbtEnvironmentsListSortField +from .connections_dbt_get_dbt_configured_response import ConnectionsDbtGetDbtConfiguredResponse +from .connections_dbt_get_dbt_not_configured_response import ConnectionsDbtGetDbtNotConfiguredResponse +from .connections_dbt_update_connections_dbt_update_body import ConnectionsDbtUpdateConnectionsDbtUpdateBody +from .connections_dbt_update_connections_dbt_update_body_project_root_path_type_1 import ( + ConnectionsDbtUpdateConnectionsDbtUpdateBodyProjectRootPathType1, +) +from .connections_dbt_update_connections_dbt_update_response import ConnectionsDbtUpdateConnectionsDbtUpdateResponse +from .connections_delete_connections_delete_response import ConnectionsDeleteConnectionsDeleteResponse +from .connections_get_connections_get_response import ConnectionsGetConnectionsGetResponse +from .connections_get_connections_get_response_connection import ConnectionsGetConnectionsGetResponseConnection +from .connections_get_connections_get_response_connection_dialect import ( + ConnectionsGetConnectionsGetResponseConnectionDialect, +) +from .connections_list_connections_list_response import ConnectionsListConnectionsListResponse +from .connections_list_connections_list_response_connection import ConnectionsListConnectionsListResponseConnection +from .connections_list_connections_list_response_connection_dialect import ( + ConnectionsListConnectionsListResponseConnectionDialect, +) +from .connections_list_sort_direction import ConnectionsListSortDirection +from .connections_list_sort_field import ConnectionsListSortField +from .connections_schedules_create_connections_schedules_create_body import ( + ConnectionsSchedulesCreateConnectionsSchedulesCreateBody, +) +from .connections_schedules_create_connections_schedules_create_response import ( + ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse, +) +from .connections_schedules_delete_connections_schedules_delete_response import ( + ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse, +) +from .connections_schedules_get_connections_schedules_get_response import ( + ConnectionsSchedulesGetConnectionsSchedulesGetResponse, +) +from .connections_schedules_list_connections_schedules_list_response import ( + ConnectionsSchedulesListConnectionsSchedulesListResponse, +) +from .connections_schedules_list_connections_schedules_list_response_connection_schedule import ( + ConnectionsSchedulesListConnectionsSchedulesListResponseConnectionSchedule, +) +from .connections_schedules_update_connections_schedules_update_body import ( + ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody, +) +from .connections_schedules_update_connections_schedules_update_response import ( + ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse, +) +from .connections_update_connections_update_body import ConnectionsUpdateConnectionsUpdateBody +from .connections_update_connections_update_body_environment_user_attribute_type_0 import ( + ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0, +) +from .connections_update_connections_update_response import ConnectionsUpdateConnectionsUpdateResponse +from .containers_item import ContainersItem +from .content_filter_mode import ContentFilterMode +from .content_list_response import ContentListResponse +from .content_list_response_records_item_type_0 import ContentListResponseRecordsItemType0 +from .content_list_response_records_item_type_0_type import ContentListResponseRecordsItemType0Type +from .content_list_response_records_item_type_1 import ContentListResponseRecordsItemType1 +from .content_list_response_records_item_type_1_count import ContentListResponseRecordsItemType1Count +from .content_list_response_records_item_type_1_owner import ContentListResponseRecordsItemType1Owner +from .content_list_response_records_item_type_1_scope import ContentListResponseRecordsItemType1Scope +from .content_list_response_records_item_type_1_type import ContentListResponseRecordsItemType1Type +from .content_list_scope import ContentListScope +from .content_list_sort_direction import ContentListSortDirection +from .content_list_sort_field import ContentListSortField +from .content_share_scope import ContentShareScope +from .control_patch_external import ControlPatchExternal +from .control_read_external import ControlReadExternal +from .controls_patch_external import ControlsPatchExternal +from .controls_read_external import ControlsReadExternal +from .create_model_schema_base import CreateModelSchemaBase +from .create_model_schema_base_access_grants_item import CreateModelSchemaBaseAccessGrantsItem +from .create_model_schema_base_access_grants_item_code_comments import CreateModelSchemaBaseAccessGrantsItemCodeComments +from .create_model_schema_base_model_kind_type_0 import CreateModelSchemaBaseModelKindType0 +from .create_model_schema_base_model_kind_type_1 import CreateModelSchemaBaseModelKindType1 +from .create_model_schema_base_model_kind_type_2 import CreateModelSchemaBaseModelKindType2 +from .create_model_schema_base_model_kind_type_3 import CreateModelSchemaBaseModelKindType3 +from .dashboard_filters_response import DashboardFiltersResponse +from .dashboards_download_body import DashboardsDownloadBody +from .dashboards_download_body_format import DashboardsDownloadBodyFormat +from .dashboards_download_body_paper_format import DashboardsDownloadBodyPaperFormat +from .dashboards_download_body_paper_orientation import DashboardsDownloadBodyPaperOrientation +from .dashboards_download_response import DashboardsDownloadResponse +from .dashboards_update_filters_body import DashboardsUpdateFiltersBody +from .dashboards_update_filters_body_controls import DashboardsUpdateFiltersBodyControls +from .dashboards_update_filters_body_controls_additional_property import ( + DashboardsUpdateFiltersBodyControlsAdditionalProperty, +) +from .dashboards_update_filters_body_filters import DashboardsUpdateFiltersBodyFilters +from .dashboards_update_filters_body_filters_additional_property import ( + DashboardsUpdateFiltersBodyFiltersAdditionalProperty, +) +from .dbt_environment_create_body import DbtEnvironmentCreateBody +from .dbt_environment_delete_response import DbtEnvironmentDeleteResponse +from .dbt_environment_item import DbtEnvironmentItem +from .dbt_environment_list_response import DbtEnvironmentListResponse +from .dbt_environment_response_variable import DbtEnvironmentResponseVariable +from .dbt_environment_update_body import DbtEnvironmentUpdateBody +from .dbt_environment_variable import DbtEnvironmentVariable +from .dbt_environment_variable_update import DbtEnvironmentVariableUpdate +from .dbt_exposure import DbtExposure +from .dbt_exposure_owner import DbtExposureOwner +from .dbt_exposure_type import DbtExposureType +from .dbt_exposure_with_meta import DbtExposureWithMeta +from .document import Document +from .document_count import DocumentCount +from .document_export_response import DocumentExportResponse +from .document_export_response_document import DocumentExportResponseDocument +from .document_export_response_file_uploads import DocumentExportResponseFileUploads +from .document_export_response_query_models import DocumentExportResponseQueryModels +from .document_favorite_user import DocumentFavoriteUser +from .document_folder_type_0 import DocumentFolderType0 +from .document_folder_type_0_scope import DocumentFolderType0Scope +from .document_import_body import DocumentImportBody +from .document_import_body_document import DocumentImportBodyDocument +from .document_import_body_export_version import DocumentImportBodyExportVersion +from .document_import_body_file_uploads import DocumentImportBodyFileUploads +from .document_import_body_query_models import DocumentImportBodyQueryModels +from .document_import_response import DocumentImportResponse +from .document_owner import DocumentOwner +from .document_scope import DocumentScope +from .document_type import DocumentType +from .documents_access_list_access_source import DocumentsAccessListAccessSource +from .documents_access_list_response import DocumentsAccessListResponse +from .documents_access_list_sort_direction import DocumentsAccessListSortDirection +from .documents_access_list_type import DocumentsAccessListType +from .documents_add_permits_body import DocumentsAddPermitsBody +from .documents_add_permits_body_role import DocumentsAddPermitsBodyRole +from .documents_bulk_update_labels_body import DocumentsBulkUpdateLabelsBody +from .documents_bulk_update_labels_response import DocumentsBulkUpdateLabelsResponse +from .documents_create_body import DocumentsCreateBody +from .documents_create_body_query_presentations_item import DocumentsCreateBodyQueryPresentationsItem +from .documents_create_body_query_presentations_item_query import DocumentsCreateBodyQueryPresentationsItemQuery +from .documents_create_draft_body import DocumentsCreateDraftBody +from .documents_create_draft_response import DocumentsCreateDraftResponse +from .documents_create_response import DocumentsCreateResponse +from .documents_create_response_dashboard import DocumentsCreateResponseDashboard +from .documents_create_response_workbook import DocumentsCreateResponseWorkbook +from .documents_discard_draft_body import DocumentsDiscardDraftBody +from .documents_discard_draft_response import DocumentsDiscardDraftResponse +from .documents_duplicate_body import DocumentsDuplicateBody +from .documents_duplicate_body_scope import DocumentsDuplicateBodyScope +from .documents_duplicate_response import DocumentsDuplicateResponse +from .documents_get_permissions_response import DocumentsGetPermissionsResponse +from .documents_get_queries_response import DocumentsGetQueriesResponse +from .documents_get_queries_response_queries_item import DocumentsGetQueriesResponseQueriesItem +from .documents_get_response import DocumentsGetResponse +from .documents_list_favorites_response import DocumentsListFavoritesResponse +from .documents_list_favorites_sort_direction import DocumentsListFavoritesSortDirection +from .documents_list_response import DocumentsListResponse +from .documents_list_sort_direction import DocumentsListSortDirection +from .documents_list_sort_field import DocumentsListSortField +from .documents_move_body import DocumentsMoveBody +from .documents_move_body_scope import DocumentsMoveBodyScope +from .documents_put_body import DocumentsPutBody +from .documents_put_query_presentation import DocumentsPutQueryPresentation +from .documents_put_query_presentation_ai_config import DocumentsPutQueryPresentationAiConfig +from .documents_put_query_presentation_ai_config_description import DocumentsPutQueryPresentationAiConfigDescription +from .documents_put_query_presentation_ai_config_sub_title import DocumentsPutQueryPresentationAiConfigSubTitle +from .documents_put_query_presentation_chart_type_type_1 import DocumentsPutQueryPresentationChartTypeType1 +from .documents_put_query_presentation_chart_type_type_2_type_1 import DocumentsPutQueryPresentationChartTypeType2Type1 +from .documents_put_query_presentation_chart_type_type_3_type_1 import DocumentsPutQueryPresentationChartTypeType3Type1 +from .documents_put_response import DocumentsPutResponse +from .documents_revoke_permits_body import DocumentsRevokePermitsBody +from .documents_transfer_ownership_body import DocumentsTransferOwnershipBody +from .documents_update_body import DocumentsUpdateBody +from .documents_update_permission_settings_body import DocumentsUpdatePermissionSettingsBody +from .documents_update_permission_settings_body_organization_role import ( + DocumentsUpdatePermissionSettingsBodyOrganizationRole, +) +from .documents_update_permits_body import DocumentsUpdatePermitsBody +from .documents_update_permits_body_role import DocumentsUpdatePermitsBodyRole +from .documents_update_response import DocumentsUpdateResponse +from .documents_upgrade_layout_body import DocumentsUpgradeLayoutBody +from .documents_upgrade_layout_response import DocumentsUpgradeLayoutResponse +from .documents_v2_create_body import DocumentsV2CreateBody +from .documents_v2_create_draft_body import DocumentsV2CreateDraftBody +from .documents_v2_create_response import DocumentsV2CreateResponse +from .documents_v2_get_draft_pretty import DocumentsV2GetDraftPretty +from .documents_v2_get_pretty import DocumentsV2GetPretty +from .documents_v2_patch_draft_body import DocumentsV2PatchDraftBody +from .documents_v2_patch_draft_response import DocumentsV2PatchDraftResponse +from .documents_v2_publish_draft_response import DocumentsV2PublishDraftResponse +from .documents_v2_read_response import DocumentsV2ReadResponse +from .documents_v2_update_identifier_body import DocumentsV2UpdateIdentifierBody +from .documents_v2_update_identifier_response import DocumentsV2UpdateIdentifierResponse +from .email_recipient import EmailRecipient +from .embed_sso_generate_session_body import EmbedSsoGenerateSessionBody +from .embed_sso_generate_session_body_user_attributes import EmbedSsoGenerateSessionBodyUserAttributes +from .embed_sso_generate_session_response import EmbedSsoGenerateSessionResponse +from .eval_api_error_400 import EvalApiError400 +from .eval_api_error_401 import EvalApiError401 +from .eval_api_error_403 import EvalApiError403 +from .eval_api_error_404 import EvalApiError404 +from .eval_api_error_422 import EvalApiError422 +from .eval_api_error_429 import EvalApiError429 +from .eval_api_error_500 import EvalApiError500 +from .eval_api_error_503 import EvalApiError503 +from .eval_prompt import EvalPrompt +from .eval_prompt_set import EvalPromptSet +from .eval_prompt_set_list_item import EvalPromptSetListItem +from .eval_prompt_sets_create_body import EvalPromptSetsCreateBody +from .eval_prompt_sets_create_body_prompts_item import EvalPromptSetsCreateBodyPromptsItem +from .eval_prompt_sets_create_response import EvalPromptSetsCreateResponse +from .eval_prompt_sets_delete_response import EvalPromptSetsDeleteResponse +from .eval_prompt_sets_get_response import EvalPromptSetsGetResponse +from .eval_prompt_sets_list_response import EvalPromptSetsListResponse +from .eval_prompt_sets_unarchive_response import EvalPromptSetsUnarchiveResponse +from .eval_prompt_sets_update_body import EvalPromptSetsUpdateBody +from .eval_prompt_sets_update_body_prompts_item import EvalPromptSetsUpdateBodyPromptsItem +from .eval_prompt_sets_update_response import EvalPromptSetsUpdateResponse +from .eval_run_detail import EvalRunDetail +from .eval_run_detail_status import EvalRunDetailStatus +from .eval_run_list_item import EvalRunListItem +from .eval_run_list_item_status import EvalRunListItemStatus +from .eval_run_result import EvalRunResult +from .eval_run_result_agentic_job import EvalRunResultAgenticJob +from .eval_run_result_agentic_job_state import EvalRunResultAgenticJobState +from .eval_run_stats import EvalRunStats +from .eval_runs_cancel_response import EvalRunsCancelResponse +from .eval_runs_create_body import EvalRunsCreateBody +from .eval_runs_create_body_run_config import EvalRunsCreateBodyRunConfig +from .eval_runs_create_response import EvalRunsCreateResponse +from .eval_runs_delete_response import EvalRunsDeleteResponse +from .eval_runs_get_response import EvalRunsGetResponse +from .eval_runs_list_response import EvalRunsListResponse +from .eval_runs_unarchive_response import EvalRunsUnarchiveResponse +from .folders_add_permissions_body import FoldersAddPermissionsBody +from .folders_add_permissions_body_role import FoldersAddPermissionsBodyRole +from .folders_add_permissions_response import FoldersAddPermissionsResponse +from .folders_create_body import FoldersCreateBody +from .folders_create_body_scope import FoldersCreateBodyScope +from .folders_create_response import FoldersCreateResponse +from .folders_create_response_scope import FoldersCreateResponseScope +from .folders_delete_response import FoldersDeleteResponse +from .folders_get_permissions_response import FoldersGetPermissionsResponse +from .folders_get_permissions_response_permits_item import FoldersGetPermissionsResponsePermitsItem +from .folders_list_response import FoldersListResponse +from .folders_list_response_records_item import FoldersListResponseRecordsItem +from .folders_list_response_records_item_count import FoldersListResponseRecordsItemCount +from .folders_list_scope import FoldersListScope +from .folders_list_sort_direction import FoldersListSortDirection +from .folders_list_sort_field import FoldersListSortField +from .folders_revoke_permissions_body import FoldersRevokePermissionsBody +from .folders_revoke_permissions_response import FoldersRevokePermissionsResponse +from .folders_update_body import FoldersUpdateBody +from .folders_update_permissions_body import FoldersUpdatePermissionsBody +from .folders_update_permissions_body_role import FoldersUpdatePermissionsBodyRole +from .folders_update_permissions_response import FoldersUpdatePermissionsResponse +from .folders_update_response import FoldersUpdateResponse +from .grid_container import GridContainer +from .ignore_suggestion_body import IgnoreSuggestionBody +from .internal_folder_type_0 import InternalFolderType0 +from .job_created_response import JobCreatedResponse +from .jobs_get_status_response import JobsGetStatusResponse +from .jobs_get_status_response_status import JobsGetStatusResponseStatus +from .json_value import JsonValue +from .labels_create_body import LabelsCreateBody +from .labels_create_response import LabelsCreateResponse +from .labels_get_response import LabelsGetResponse +from .labels_list_response import LabelsListResponse +from .labels_list_response_labels_item import LabelsListResponseLabelsItem +from .labels_update_body import LabelsUpdateBody +from .labels_update_response import LabelsUpdateResponse +from .model_suggestion import ModelSuggestion +from .model_suggestions_list_response import ModelSuggestionsListResponse +from .model_suggestions_list_status import ModelSuggestionsListStatus +from .model_yaml_create_request_body import ModelYamlCreateRequestBody +from .model_yaml_create_request_body_mode import ModelYamlCreateRequestBodyMode +from .model_yaml_response import ModelYamlResponse +from .model_yaml_response_checksums import ModelYamlResponseChecksums +from .model_yaml_response_files import ModelYamlResponseFiles +from .model_yaml_response_view_names import ModelYamlResponseViewNames +from .models_branch_dbt_body import ModelsBranchDbtBody +from .models_cache_reset_body import ModelsCacheResetBody +from .models_cache_reset_response import ModelsCacheResetResponse +from .models_cache_reset_response_cache_reset import ModelsCacheResetResponseCacheReset +from .models_commit_body import ModelsCommitBody +from .models_commit_response import ModelsCommitResponse +from .models_content_validator_get_find_type import ModelsContentValidatorGetFindType +from .models_content_validator_get_response import ModelsContentValidatorGetResponse +from .models_content_validator_get_response_branch_type_0 import ModelsContentValidatorGetResponseBranchType0 +from .models_content_validator_replace_body import ModelsContentValidatorReplaceBody +from .models_content_validator_replace_body_find_or_replace_type import ( + ModelsContentValidatorReplaceBodyFindOrReplaceType, +) +from .models_content_validator_replace_response import ModelsContentValidatorReplaceResponse +from .models_create_field_body import ModelsCreateFieldBody +from .models_create_field_body_aggregate_type import ModelsCreateFieldBodyAggregateType +from .models_create_models_create_response import ModelsCreateModelsCreateResponse +from .models_create_models_create_response_model import ModelsCreateModelsCreateResponseModel +from .models_dbt_exposures_response import ModelsDbtExposuresResponse +from .models_dbt_exposures_sort_direction import ModelsDbtExposuresSortDirection +from .models_delete_topic_mode import ModelsDeleteTopicMode +from .models_delete_view_mode import ModelsDeleteViewMode +from .models_get_schemas_response import ModelsGetSchemasResponse +from .models_get_topic_response import ModelsGetTopicResponse +from .models_get_topic_response_topic import ModelsGetTopicResponseTopic +from .models_get_topic_response_topic_relationships_item import ModelsGetTopicResponseTopicRelationshipsItem +from .models_get_topic_response_topic_views_item import ModelsGetTopicResponseTopicViewsItem +from .models_get_view_response import ModelsGetViewResponse +from .models_get_view_response_views_item import ModelsGetViewResponseViewsItem +from .models_get_view_response_views_item_fields_item import ModelsGetViewResponseViewsItemFieldsItem +from .models_get_view_response_views_item_fields_item_type import ModelsGetViewResponseViewsItemFieldsItemType +from .models_git_create_body import ModelsGitCreateBody +from .models_git_create_body_auth_method import ModelsGitCreateBodyAuthMethod +from .models_git_create_body_git_service_provider import ModelsGitCreateBodyGitServiceProvider +from .models_git_create_body_require_pull_request import ModelsGitCreateBodyRequirePullRequest +from .models_git_create_response import ModelsGitCreateResponse +from .models_git_create_response_auth_method import ModelsGitCreateResponseAuthMethod +from .models_git_create_response_require_pull_request import ModelsGitCreateResponseRequirePullRequest +from .models_git_delete_response import ModelsGitDeleteResponse +from .models_git_get_response import ModelsGitGetResponse +from .models_git_get_response_auth_method import ModelsGitGetResponseAuthMethod +from .models_git_get_response_require_pull_request import ModelsGitGetResponseRequirePullRequest +from .models_git_sync_body import ModelsGitSyncBody +from .models_git_sync_response import ModelsGitSyncResponse +from .models_git_update_body import ModelsGitUpdateBody +from .models_git_update_body_auth_method import ModelsGitUpdateBodyAuthMethod +from .models_git_update_body_git_service_provider import ModelsGitUpdateBodyGitServiceProvider +from .models_git_update_body_require_pull_request import ModelsGitUpdateBodyRequirePullRequest +from .models_git_update_response import ModelsGitUpdateResponse +from .models_git_update_response_auth_method import ModelsGitUpdateResponseAuthMethod +from .models_git_update_response_require_pull_request import ModelsGitUpdateResponseRequirePullRequest +from .models_list_include_deleted import ModelsListIncludeDeleted +from .models_list_model_kind import ModelsListModelKind +from .models_list_response import ModelsListResponse +from .models_list_response_records_item import ModelsListResponseRecordsItem +from .models_list_response_records_item_branches_item import ModelsListResponseRecordsItemBranchesItem +from .models_list_sort_direction import ModelsListSortDirection +from .models_list_sort_field import ModelsListSortField +from .models_list_topics_response import ModelsListTopicsResponse +from .models_list_topics_response_topics_item import ModelsListTopicsResponseTopicsItem +from .models_merge_branch_body import ModelsMergeBranchBody +from .models_merge_branch_response import ModelsMergeBranchResponse +from .models_migrate_body import ModelsMigrateBody +from .models_refresh_hard_refresh import ModelsRefreshHardRefresh +from .models_refresh_response import ModelsRefreshResponse +from .models_refresh_response_status import ModelsRefreshResponseStatus +from .models_update_body import ModelsUpdateBody +from .models_update_field_body import ModelsUpdateFieldBody +from .models_update_field_body_filters import ModelsUpdateFieldBodyFilters +from .models_update_field_body_group_filters_item import ModelsUpdateFieldBodyGroupFiltersItem +from .models_update_response import ModelsUpdateResponse +from .models_update_response_model import ModelsUpdateResponseModel +from .models_update_topic_body import ModelsUpdateTopicBody +from .models_update_view_body import ModelsUpdateViewBody +from .models_validate_response import ModelsValidateResponse +from .models_validate_response_issues_item import ModelsValidateResponseIssuesItem +from .models_validate_response_issues_item_severity import ModelsValidateResponseIssuesItemSeverity +from .models_yaml_delete_mode import ModelsYamlDeleteMode +from .models_yaml_get_mode import ModelsYamlGetMode +from .owner_internal import OwnerInternal +from .page_container import PageContainer +from .page_info import PageInfo +from .query_presentation_patch_external import QueryPresentationPatchExternal +from .query_presentation_read_external import QueryPresentationReadExternal +from .query_presentations_patch_external import QueryPresentationsPatchExternal +from .query_presentations_read_external import QueryPresentationsReadExternal +from .query_run_body import QueryRunBody +from .query_run_body_cache import QueryRunBodyCache +from .query_run_body_result_type import QueryRunBodyResultType +from .query_run_response import QueryRunResponse +from .query_timeout_response import QueryTimeoutResponse +from .query_wait_response import QueryWaitResponse +from .reference_container import ReferenceContainer +from .role_assignment_result import RoleAssignmentResult +from .role_origin_type_0 import RoleOriginType0 +from .role_origin_type_0_type import RoleOriginType0Type +from .role_origin_type_1 import RoleOriginType1 +from .role_origin_type_1_type import RoleOriginType1Type +from .role_origin_type_2 import RoleOriginType2 +from .role_origin_type_2_type import RoleOriginType2Type +from .role_origin_type_3 import RoleOriginType3 +from .role_origin_type_3_type import RoleOriginType3Type +from .routine_create_body import RoutineCreateBody +from .routine_create_response import RoutineCreateResponse +from .routine_delete_response import RoutineDeleteResponse +from .routine_email_destination import RoutineEmailDestination +from .routine_email_destination_response import RoutineEmailDestinationResponse +from .routine_email_destination_response_type import RoutineEmailDestinationResponseType +from .routine_email_destination_type import RoutineEmailDestinationType +from .routine_last_run_type_0 import RoutineLastRunType0 +from .routine_response import RoutineResponse +from .routine_slack_destination import RoutineSlackDestination +from .routine_slack_destination_slack_recipient_type import RoutineSlackDestinationSlackRecipientType +from .routine_slack_destination_type import RoutineSlackDestinationType +from .routine_trigger_response import RoutineTriggerResponse +from .routine_update_body import RoutineUpdateBody +from .routines_list_response import RoutinesListResponse +from .routines_list_sort_direction import RoutinesListSortDirection +from .schedule_suggestions_body import ScheduleSuggestionsBody +from .schedule_suggestions_response import ScheduleSuggestionsResponse +from .schedule_suggestions_response_status import ScheduleSuggestionsResponseStatus +from .schedules_add_recipients_body import SchedulesAddRecipientsBody +from .schedules_add_recipients_response import SchedulesAddRecipientsResponse +from .schedules_create_schedules_create_body import SchedulesCreateSchedulesCreateBody +from .schedules_create_schedules_create_body_condition_type import SchedulesCreateSchedulesCreateBodyConditionType +from .schedules_create_schedules_create_body_destination_type import SchedulesCreateSchedulesCreateBodyDestinationType +from .schedules_create_schedules_create_body_format import SchedulesCreateSchedulesCreateBodyFormat +from .schedules_create_schedules_create_body_recipients_item import SchedulesCreateSchedulesCreateBodyRecipientsItem +from .schedules_create_schedules_create_response import SchedulesCreateSchedulesCreateResponse +from .schedules_get_destination import SchedulesGetDestination +from .schedules_get_recipient import SchedulesGetRecipient +from .schedules_get_recipient_membership import SchedulesGetRecipientMembership +from .schedules_get_recipient_membership_user import SchedulesGetRecipientMembershipUser +from .schedules_get_response import SchedulesGetResponse +from .schedules_get_response_owner import SchedulesGetResponseOwner +from .schedules_list_content_type import SchedulesListContentType +from .schedules_list_destination import SchedulesListDestination +from .schedules_list_item import SchedulesListItem +from .schedules_list_item_alert import SchedulesListItemAlert +from .schedules_list_response_200 import SchedulesListResponse200 +from .schedules_list_schedule_type import SchedulesListScheduleType +from .schedules_list_sort_direction import SchedulesListSortDirection +from .schedules_list_sort_field import SchedulesListSortField +from .schedules_list_status import SchedulesListStatus +from .schedules_recipients_get_response import SchedulesRecipientsGetResponse +from .schedules_recipients_get_response_type import SchedulesRecipientsGetResponseType +from .schedules_remove_recipients_body import SchedulesRemoveRecipientsBody +from .schedules_remove_recipients_response import SchedulesRemoveRecipientsResponse +from .schedules_transfer_ownership_body import SchedulesTransferOwnershipBody +from .scim_group_response import ScimGroupResponse +from .scim_group_response_members_item import ScimGroupResponseMembersItem +from .scim_groups_create_body import ScimGroupsCreateBody +from .scim_groups_create_body_members_item import ScimGroupsCreateBodyMembersItem +from .scim_groups_get_excluded_attributes import ScimGroupsGetExcludedAttributes +from .scim_groups_list_excluded_attributes import ScimGroupsListExcludedAttributes +from .scim_groups_list_response import ScimGroupsListResponse +from .scim_groups_patch_body import ScimGroupsPatchBody +from .scim_groups_patch_body_operations_item_type_0 import ScimGroupsPatchBodyOperationsItemType0 +from .scim_groups_patch_body_operations_item_type_0_op import ScimGroupsPatchBodyOperationsItemType0Op +from .scim_groups_patch_body_operations_item_type_0_value import ScimGroupsPatchBodyOperationsItemType0Value +from .scim_groups_patch_body_operations_item_type_1 import ScimGroupsPatchBodyOperationsItemType1 +from .scim_groups_patch_body_operations_item_type_1_op import ScimGroupsPatchBodyOperationsItemType1Op +from .scim_groups_patch_body_operations_item_type_2 import ScimGroupsPatchBodyOperationsItemType2 +from .scim_groups_patch_body_operations_item_type_2_op import ScimGroupsPatchBodyOperationsItemType2Op +from .scim_groups_patch_body_operations_item_type_2_path import ScimGroupsPatchBodyOperationsItemType2Path +from .scim_groups_patch_body_operations_item_type_2_value_item import ScimGroupsPatchBodyOperationsItemType2ValueItem +from .scim_groups_patch_body_operations_item_type_3 import ScimGroupsPatchBodyOperationsItemType3 +from .scim_groups_patch_body_operations_item_type_3_op import ScimGroupsPatchBodyOperationsItemType3Op +from .scim_groups_patch_body_operations_item_type_3_path import ScimGroupsPatchBodyOperationsItemType3Path +from .scim_groups_patch_body_operations_item_type_3_value_type_0_item import ( + ScimGroupsPatchBodyOperationsItemType3ValueType0Item, +) +from .scim_groups_patch_body_schemas_item import ScimGroupsPatchBodySchemasItem +from .scim_groups_replace_body import ScimGroupsReplaceBody +from .scim_groups_replace_body_members_item import ScimGroupsReplaceBodyMembersItem +from .scim_user_create_request import ScimUserCreateRequest +from .scim_user_create_request_urnomniparams_10_user_attribute import ScimUserCreateRequestUrnomniparams10UserAttribute +from .scim_user_create_request_urnomniparams_10_user_attribute_additional_property_type_6 import ( + ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6, +) +from .scim_user_patch_request import ScimUserPatchRequest +from .scim_user_patch_request_operations_item import ScimUserPatchRequestOperationsItem +from .scim_user_patch_request_operations_item_op import ScimUserPatchRequestOperationsItemOp +from .scim_user_patch_request_operations_item_value_type_6 import ScimUserPatchRequestOperationsItemValueType6 +from .scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user import ( + ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20User, +) +from .scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6 import ( + ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6, +) +from .scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute import ( + ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttribute, +) +from .scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute_additional_property_type_6 import ( + ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6, +) +from .scim_user_patch_request_schemas_item import ScimUserPatchRequestSchemasItem +from .scim_user_put_request import ScimUserPutRequest +from .scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user import ( + ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20User, +) +from .scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6 import ( + ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6, +) +from .scim_user_put_request_urnomniparams_10_user_attribute import ScimUserPutRequestUrnomniparams10UserAttribute +from .scim_user_put_request_urnomniparams_10_user_attribute_additional_property_type_6 import ( + ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6, +) +from .scim_user_response import ScimUserResponse +from .scim_users_list_response import ScimUsersListResponse +from .settings_patch_external import SettingsPatchExternal +from .settings_patch_external_custom_text_type_0 import SettingsPatchExternalCustomTextType0 +from .settings_patch_external_run_queries_on_type_1 import SettingsPatchExternalRunQueriesOnType1 +from .settings_patch_external_run_queries_on_type_2_type_1 import SettingsPatchExternalRunQueriesOnType2Type1 +from .settings_patch_external_run_queries_on_type_3_type_1 import SettingsPatchExternalRunQueriesOnType3Type1 +from .settings_read_external import SettingsReadExternal +from .settings_read_external_custom_text_type_0 import SettingsReadExternalCustomTextType0 +from .settings_read_external_run_queries_on_type_1 import SettingsReadExternalRunQueriesOnType1 +from .settings_read_external_run_queries_on_type_2_type_1 import SettingsReadExternalRunQueriesOnType2Type1 +from .settings_read_external_run_queries_on_type_3_type_1 import SettingsReadExternalRunQueriesOnType3Type1 +from .stack_container import StackContainer +from .success_response import SuccessResponse +from .suggestion_context_edit import SuggestionContextEdit +from .suggestion_evidence_item import SuggestionEvidenceItem +from .suggestion_evidence_item_type import SuggestionEvidenceItemType +from .suggestion_proposed_changes import SuggestionProposedChanges +from .suggestion_proposed_changes_kind import SuggestionProposedChangesKind +from .upload import Upload +from .upload_create_body import UploadCreateBody +from .upload_create_response import UploadCreateResponse +from .upload_delete_response import UploadDeleteResponse +from .upload_uploaded_by_user_type_0 import UploadUploadedByUserType0 +from .uploads_list_response import UploadsListResponse +from .uploads_list_sort_direction import UploadsListSortDirection +from .uploads_list_sort_field import UploadsListSortField +from .uploads_list_type import UploadsListType +from .user_attributes_list_response import UserAttributesListResponse +from .user_attributes_list_response_records_item import UserAttributesListResponseRecordsItem +from .user_attributes_list_response_records_item_type import UserAttributesListResponseRecordsItemType +from .user_group_recipient import UserGroupRecipient +from .user_group_role_assignment_result import UserGroupRoleAssignmentResult +from .user_group_role_origin import UserGroupRoleOrigin +from .user_group_role_origin_type import UserGroupRoleOriginType +from .user_groups_assign_model_role_body import UserGroupsAssignModelRoleBody +from .user_groups_assign_model_role_response import UserGroupsAssignModelRoleResponse +from .user_groups_get_model_roles_response import UserGroupsGetModelRolesResponse +from .users_assign_model_role_body import UsersAssignModelRoleBody +from .users_assign_model_role_response import UsersAssignModelRoleResponse +from .users_create_email_only_body import UsersCreateEmailOnlyBody +from .users_create_email_only_body_user_attributes import UsersCreateEmailOnlyBodyUserAttributes +from .users_create_email_only_bulk_body import UsersCreateEmailOnlyBulkBody +from .users_create_email_only_bulk_body_users_item import UsersCreateEmailOnlyBulkBodyUsersItem +from .users_create_email_only_bulk_body_users_item_user_attributes import ( + UsersCreateEmailOnlyBulkBodyUsersItemUserAttributes, +) +from .users_create_email_only_bulk_response import UsersCreateEmailOnlyBulkResponse +from .users_create_email_only_bulk_response_results_item import UsersCreateEmailOnlyBulkResponseResultsItem +from .users_create_email_only_response import UsersCreateEmailOnlyResponse +from .users_get_model_roles_response import UsersGetModelRolesResponse +from .users_list_email_only_response import UsersListEmailOnlyResponse +from .users_list_email_only_response_records_item import UsersListEmailOnlyResponseRecordsItem +from .users_list_email_only_response_records_item_user_attributes import ( + UsersListEmailOnlyResponseRecordsItemUserAttributes, +) +from .users_list_email_only_sort_direction import UsersListEmailOnlySortDirection +from .whoami_model_role import WhoamiModelRole +from .whoami_model_role_permissions_item import WhoamiModelRolePermissionsItem +from .whoami_response import WhoamiResponse +from .whoami_response_key_scope import WhoamiResponseKeyScope +from .whoami_response_org_role import WhoamiResponseOrgRole +from .whoami_response_roles_by_model import WhoamiResponseRolesByModel +from .whoami_user import WhoamiUser + +__all__ = ( + "AiAgentAction", + "AiAgentActionKind", + "AiAgentActionsResponse", + "AiBrandingResponse", + "AiConversation", + "AiConversationDetailResponse", + "AiConversationMessage", + "AiConversationMessageRole", + "AiConversationsListResponse", + "AiCreditControlsResponse", + "AiCreditControlsUpdateBody", + "AiCreditControlsUsersListResponse", + "AiCreditControlsUsersListResponseRecordsItem", + "AiCreditShutoffError", + "AiCreditShutoffErrorCode", + "AiEvalPromptSetsListArchived", + "AiEvalRunsListArchived", + "AiGenerateQueryBody", + "AiGenerateQueryResponse", + "AiGenerateQueryResponseErrorType0", + "AiGenerateQueryResponseResult", + "AiJobAction", + "AiJobActionQueryResult", + "AiJobActionQueryResultQuery", + "AiJobActionQueryResultStatus", + "AiJobCancelResponse", + "AiJobCancelResponseState", + "AiJobResultResponse", + "AiJobStatusResponse", + "AiJobStatusResponseError", + "AiJobStatusResponseProgressType0", + "AiJobStatusResponseState", + "AiJobSubmitBody", + "AiJobSubmitBodyWebhookMetadata", + "AiJobSubmitResponse", + "AiPickTopicBody", + "AiPickTopicResponse", + "AiQuerySort", + "AiSearchOmniDocsBody", + "AiSearchOmniDocsResponse", + "AiSearchOmniDocsResponseSourcesItem", + "AiSemanticQuery", + "AiTopicParams", + "AiUserCreditLimitEntry", + "AiUserCreditLimitsResponse", + "AiUserCreditLimitsResponseUsersItem", + "AiUserCreditLimitsUpdateBody", + "ApiDocument", + "ApiDocumentCount", + "ApiDraft", + "ApiDraftActor", + "ApiDraftBranchType0", + "ApiDraftStatus", + "ApiError400", + "ApiError401", + "ApiError403", + "ApiError404", + "ApiError409", + "ApiError422", + "ApiError429", + "ApiKey", + "ApiKeyDeleteResponse", + "ApiKeyListResponse", + "ApiKeysListSortDirection", + "ApiKeysListSortField", + "ApiKeysListType", + "ApiKeyType", + "ApiKeyUpdateBody", + "ApiVisConfig", + "CompositeFilter", + "CompositeFilterConjunction", + "CompositeFilterFiltersItemType0", + "CompositeFilterFiltersItemType0AppliedLabels", + "CompositeFilterFiltersItemType0Kind", + "CompositeFilterFiltersItemType0Type", + "CompositeFilterFiltersItemType1", + "CompositeFilterFiltersItemType1Kind", + "CompositeFilterFiltersItemType1Type", + "CompositeFilterFiltersItemType2", + "CompositeFilterFiltersItemType2Kind", + "CompositeFilterFiltersItemType2Type", + "CompositeFilterFiltersItemType2UiTypeType1", + "CompositeFilterFiltersItemType2UiTypeType2Type1", + "CompositeFilterFiltersItemType2UiTypeType3Type1", + "CompositeFilterFiltersItemType3", + "CompositeFilterFiltersItemType3Type", + "CompositeFilterFiltersItemType4", + "CompositeFilterFiltersItemType4Type", + "CompositeFilterFiltersItemType5", + "CompositeFilterFiltersItemType5Type", + "CompositeFilterFiltersItemType5ViewQuery", + "CompositeFilterFiltersItemType5ViewQueryFilters", + "CompositeFilterFiltersItemType6", + "CompositeFilterFiltersItemType6Type", + "CompositeFilterType", + "ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody", + "ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse", + "ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponseConnectionEnvironment", + "ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse", + "ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody", + "ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse", + "ConnectionsCreateConnectionsCreateBody", + "ConnectionsCreateConnectionsCreateBodyBaseRole", + "ConnectionsCreateConnectionsCreateBodyDialect", + "ConnectionsCreateConnectionsCreateResponse", + "ConnectionsDbtDeleteConnectionsDbtDeleteResponse", + "ConnectionsDbtEnvironmentsListSortDirection", + "ConnectionsDbtEnvironmentsListSortField", + "ConnectionsDbtGetDbtConfiguredResponse", + "ConnectionsDbtGetDbtNotConfiguredResponse", + "ConnectionsDbtUpdateConnectionsDbtUpdateBody", + "ConnectionsDbtUpdateConnectionsDbtUpdateBodyProjectRootPathType1", + "ConnectionsDbtUpdateConnectionsDbtUpdateResponse", + "ConnectionsDeleteConnectionsDeleteResponse", + "ConnectionsGetConnectionsGetResponse", + "ConnectionsGetConnectionsGetResponseConnection", + "ConnectionsGetConnectionsGetResponseConnectionDialect", + "ConnectionsListConnectionsListResponse", + "ConnectionsListConnectionsListResponseConnection", + "ConnectionsListConnectionsListResponseConnectionDialect", + "ConnectionsListSortDirection", + "ConnectionsListSortField", + "ConnectionsSchedulesCreateConnectionsSchedulesCreateBody", + "ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse", + "ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse", + "ConnectionsSchedulesGetConnectionsSchedulesGetResponse", + "ConnectionsSchedulesListConnectionsSchedulesListResponse", + "ConnectionsSchedulesListConnectionsSchedulesListResponseConnectionSchedule", + "ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody", + "ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse", + "ConnectionsUpdateConnectionsUpdateBody", + "ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0", + "ConnectionsUpdateConnectionsUpdateResponse", + "ContainersItem", + "ContentFilterMode", + "ContentListResponse", + "ContentListResponseRecordsItemType0", + "ContentListResponseRecordsItemType0Type", + "ContentListResponseRecordsItemType1", + "ContentListResponseRecordsItemType1Count", + "ContentListResponseRecordsItemType1Owner", + "ContentListResponseRecordsItemType1Scope", + "ContentListResponseRecordsItemType1Type", + "ContentListScope", + "ContentListSortDirection", + "ContentListSortField", + "ContentShareScope", + "ControlPatchExternal", + "ControlReadExternal", + "ControlsPatchExternal", + "ControlsReadExternal", + "CreateModelSchemaBase", + "CreateModelSchemaBaseAccessGrantsItem", + "CreateModelSchemaBaseAccessGrantsItemCodeComments", + "CreateModelSchemaBaseModelKindType0", + "CreateModelSchemaBaseModelKindType1", + "CreateModelSchemaBaseModelKindType2", + "CreateModelSchemaBaseModelKindType3", + "DashboardFiltersResponse", + "DashboardsDownloadBody", + "DashboardsDownloadBodyFormat", + "DashboardsDownloadBodyPaperFormat", + "DashboardsDownloadBodyPaperOrientation", + "DashboardsDownloadResponse", + "DashboardsUpdateFiltersBody", + "DashboardsUpdateFiltersBodyControls", + "DashboardsUpdateFiltersBodyControlsAdditionalProperty", + "DashboardsUpdateFiltersBodyFilters", + "DashboardsUpdateFiltersBodyFiltersAdditionalProperty", + "DbtEnvironmentCreateBody", + "DbtEnvironmentDeleteResponse", + "DbtEnvironmentItem", + "DbtEnvironmentListResponse", + "DbtEnvironmentResponseVariable", + "DbtEnvironmentUpdateBody", + "DbtEnvironmentVariable", + "DbtEnvironmentVariableUpdate", + "DbtExposure", + "DbtExposureOwner", + "DbtExposureType", + "DbtExposureWithMeta", + "Document", + "DocumentCount", + "DocumentExportResponse", + "DocumentExportResponseDocument", + "DocumentExportResponseFileUploads", + "DocumentExportResponseQueryModels", + "DocumentFavoriteUser", + "DocumentFolderType0", + "DocumentFolderType0Scope", + "DocumentImportBody", + "DocumentImportBodyDocument", + "DocumentImportBodyExportVersion", + "DocumentImportBodyFileUploads", + "DocumentImportBodyQueryModels", + "DocumentImportResponse", + "DocumentOwner", + "DocumentsAccessListAccessSource", + "DocumentsAccessListResponse", + "DocumentsAccessListSortDirection", + "DocumentsAccessListType", + "DocumentsAddPermitsBody", + "DocumentsAddPermitsBodyRole", + "DocumentsBulkUpdateLabelsBody", + "DocumentsBulkUpdateLabelsResponse", + "DocumentScope", + "DocumentsCreateBody", + "DocumentsCreateBodyQueryPresentationsItem", + "DocumentsCreateBodyQueryPresentationsItemQuery", + "DocumentsCreateDraftBody", + "DocumentsCreateDraftResponse", + "DocumentsCreateResponse", + "DocumentsCreateResponseDashboard", + "DocumentsCreateResponseWorkbook", + "DocumentsDiscardDraftBody", + "DocumentsDiscardDraftResponse", + "DocumentsDuplicateBody", + "DocumentsDuplicateBodyScope", + "DocumentsDuplicateResponse", + "DocumentsGetPermissionsResponse", + "DocumentsGetQueriesResponse", + "DocumentsGetQueriesResponseQueriesItem", + "DocumentsGetResponse", + "DocumentsListFavoritesResponse", + "DocumentsListFavoritesSortDirection", + "DocumentsListResponse", + "DocumentsListSortDirection", + "DocumentsListSortField", + "DocumentsMoveBody", + "DocumentsMoveBodyScope", + "DocumentsPutBody", + "DocumentsPutQueryPresentation", + "DocumentsPutQueryPresentationAiConfig", + "DocumentsPutQueryPresentationAiConfigDescription", + "DocumentsPutQueryPresentationAiConfigSubTitle", + "DocumentsPutQueryPresentationChartTypeType1", + "DocumentsPutQueryPresentationChartTypeType2Type1", + "DocumentsPutQueryPresentationChartTypeType3Type1", + "DocumentsPutResponse", + "DocumentsRevokePermitsBody", + "DocumentsTransferOwnershipBody", + "DocumentsUpdateBody", + "DocumentsUpdatePermissionSettingsBody", + "DocumentsUpdatePermissionSettingsBodyOrganizationRole", + "DocumentsUpdatePermitsBody", + "DocumentsUpdatePermitsBodyRole", + "DocumentsUpdateResponse", + "DocumentsUpgradeLayoutBody", + "DocumentsUpgradeLayoutResponse", + "DocumentsV2CreateBody", + "DocumentsV2CreateDraftBody", + "DocumentsV2CreateResponse", + "DocumentsV2GetDraftPretty", + "DocumentsV2GetPretty", + "DocumentsV2PatchDraftBody", + "DocumentsV2PatchDraftResponse", + "DocumentsV2PublishDraftResponse", + "DocumentsV2ReadResponse", + "DocumentsV2UpdateIdentifierBody", + "DocumentsV2UpdateIdentifierResponse", + "DocumentType", + "EmailRecipient", + "EmbedSsoGenerateSessionBody", + "EmbedSsoGenerateSessionBodyUserAttributes", + "EmbedSsoGenerateSessionResponse", + "EvalApiError400", + "EvalApiError401", + "EvalApiError403", + "EvalApiError404", + "EvalApiError422", + "EvalApiError429", + "EvalApiError500", + "EvalApiError503", + "EvalPrompt", + "EvalPromptSet", + "EvalPromptSetListItem", + "EvalPromptSetsCreateBody", + "EvalPromptSetsCreateBodyPromptsItem", + "EvalPromptSetsCreateResponse", + "EvalPromptSetsDeleteResponse", + "EvalPromptSetsGetResponse", + "EvalPromptSetsListResponse", + "EvalPromptSetsUnarchiveResponse", + "EvalPromptSetsUpdateBody", + "EvalPromptSetsUpdateBodyPromptsItem", + "EvalPromptSetsUpdateResponse", + "EvalRunDetail", + "EvalRunDetailStatus", + "EvalRunListItem", + "EvalRunListItemStatus", + "EvalRunResult", + "EvalRunResultAgenticJob", + "EvalRunResultAgenticJobState", + "EvalRunsCancelResponse", + "EvalRunsCreateBody", + "EvalRunsCreateBodyRunConfig", + "EvalRunsCreateResponse", + "EvalRunsDeleteResponse", + "EvalRunsGetResponse", + "EvalRunsListResponse", + "EvalRunStats", + "EvalRunsUnarchiveResponse", + "FoldersAddPermissionsBody", + "FoldersAddPermissionsBodyRole", + "FoldersAddPermissionsResponse", + "FoldersCreateBody", + "FoldersCreateBodyScope", + "FoldersCreateResponse", + "FoldersCreateResponseScope", + "FoldersDeleteResponse", + "FoldersGetPermissionsResponse", + "FoldersGetPermissionsResponsePermitsItem", + "FoldersListResponse", + "FoldersListResponseRecordsItem", + "FoldersListResponseRecordsItemCount", + "FoldersListScope", + "FoldersListSortDirection", + "FoldersListSortField", + "FoldersRevokePermissionsBody", + "FoldersRevokePermissionsResponse", + "FoldersUpdateBody", + "FoldersUpdatePermissionsBody", + "FoldersUpdatePermissionsBodyRole", + "FoldersUpdatePermissionsResponse", + "FoldersUpdateResponse", + "GridContainer", + "IgnoreSuggestionBody", + "InternalFolderType0", + "JobCreatedResponse", + "JobsGetStatusResponse", + "JobsGetStatusResponseStatus", + "JsonValue", + "LabelsCreateBody", + "LabelsCreateResponse", + "LabelsGetResponse", + "LabelsListResponse", + "LabelsListResponseLabelsItem", + "LabelsUpdateBody", + "LabelsUpdateResponse", + "ModelsBranchDbtBody", + "ModelsCacheResetBody", + "ModelsCacheResetResponse", + "ModelsCacheResetResponseCacheReset", + "ModelsCommitBody", + "ModelsCommitResponse", + "ModelsContentValidatorGetFindType", + "ModelsContentValidatorGetResponse", + "ModelsContentValidatorGetResponseBranchType0", + "ModelsContentValidatorReplaceBody", + "ModelsContentValidatorReplaceBodyFindOrReplaceType", + "ModelsContentValidatorReplaceResponse", + "ModelsCreateFieldBody", + "ModelsCreateFieldBodyAggregateType", + "ModelsCreateModelsCreateResponse", + "ModelsCreateModelsCreateResponseModel", + "ModelsDbtExposuresResponse", + "ModelsDbtExposuresSortDirection", + "ModelsDeleteTopicMode", + "ModelsDeleteViewMode", + "ModelsGetSchemasResponse", + "ModelsGetTopicResponse", + "ModelsGetTopicResponseTopic", + "ModelsGetTopicResponseTopicRelationshipsItem", + "ModelsGetTopicResponseTopicViewsItem", + "ModelsGetViewResponse", + "ModelsGetViewResponseViewsItem", + "ModelsGetViewResponseViewsItemFieldsItem", + "ModelsGetViewResponseViewsItemFieldsItemType", + "ModelsGitCreateBody", + "ModelsGitCreateBodyAuthMethod", + "ModelsGitCreateBodyGitServiceProvider", + "ModelsGitCreateBodyRequirePullRequest", + "ModelsGitCreateResponse", + "ModelsGitCreateResponseAuthMethod", + "ModelsGitCreateResponseRequirePullRequest", + "ModelsGitDeleteResponse", + "ModelsGitGetResponse", + "ModelsGitGetResponseAuthMethod", + "ModelsGitGetResponseRequirePullRequest", + "ModelsGitSyncBody", + "ModelsGitSyncResponse", + "ModelsGitUpdateBody", + "ModelsGitUpdateBodyAuthMethod", + "ModelsGitUpdateBodyGitServiceProvider", + "ModelsGitUpdateBodyRequirePullRequest", + "ModelsGitUpdateResponse", + "ModelsGitUpdateResponseAuthMethod", + "ModelsGitUpdateResponseRequirePullRequest", + "ModelsListIncludeDeleted", + "ModelsListModelKind", + "ModelsListResponse", + "ModelsListResponseRecordsItem", + "ModelsListResponseRecordsItemBranchesItem", + "ModelsListSortDirection", + "ModelsListSortField", + "ModelsListTopicsResponse", + "ModelsListTopicsResponseTopicsItem", + "ModelsMergeBranchBody", + "ModelsMergeBranchResponse", + "ModelsMigrateBody", + "ModelsRefreshHardRefresh", + "ModelsRefreshResponse", + "ModelsRefreshResponseStatus", + "ModelSuggestion", + "ModelSuggestionsListResponse", + "ModelSuggestionsListStatus", + "ModelsUpdateBody", + "ModelsUpdateFieldBody", + "ModelsUpdateFieldBodyFilters", + "ModelsUpdateFieldBodyGroupFiltersItem", + "ModelsUpdateResponse", + "ModelsUpdateResponseModel", + "ModelsUpdateTopicBody", + "ModelsUpdateViewBody", + "ModelsValidateResponse", + "ModelsValidateResponseIssuesItem", + "ModelsValidateResponseIssuesItemSeverity", + "ModelsYamlDeleteMode", + "ModelsYamlGetMode", + "ModelYamlCreateRequestBody", + "ModelYamlCreateRequestBodyMode", + "ModelYamlResponse", + "ModelYamlResponseChecksums", + "ModelYamlResponseFiles", + "ModelYamlResponseViewNames", + "OwnerInternal", + "PageContainer", + "PageInfo", + "QueryPresentationPatchExternal", + "QueryPresentationReadExternal", + "QueryPresentationsPatchExternal", + "QueryPresentationsReadExternal", + "QueryRunBody", + "QueryRunBodyCache", + "QueryRunBodyResultType", + "QueryRunResponse", + "QueryTimeoutResponse", + "QueryWaitResponse", + "ReferenceContainer", + "RoleAssignmentResult", + "RoleOriginType0", + "RoleOriginType0Type", + "RoleOriginType1", + "RoleOriginType1Type", + "RoleOriginType2", + "RoleOriginType2Type", + "RoleOriginType3", + "RoleOriginType3Type", + "RoutineCreateBody", + "RoutineCreateResponse", + "RoutineDeleteResponse", + "RoutineEmailDestination", + "RoutineEmailDestinationResponse", + "RoutineEmailDestinationResponseType", + "RoutineEmailDestinationType", + "RoutineLastRunType0", + "RoutineResponse", + "RoutineSlackDestination", + "RoutineSlackDestinationSlackRecipientType", + "RoutineSlackDestinationType", + "RoutinesListResponse", + "RoutinesListSortDirection", + "RoutineTriggerResponse", + "RoutineUpdateBody", + "SchedulesAddRecipientsBody", + "SchedulesAddRecipientsResponse", + "SchedulesCreateSchedulesCreateBody", + "SchedulesCreateSchedulesCreateBodyConditionType", + "SchedulesCreateSchedulesCreateBodyDestinationType", + "SchedulesCreateSchedulesCreateBodyFormat", + "SchedulesCreateSchedulesCreateBodyRecipientsItem", + "SchedulesCreateSchedulesCreateResponse", + "SchedulesGetDestination", + "SchedulesGetRecipient", + "SchedulesGetRecipientMembership", + "SchedulesGetRecipientMembershipUser", + "SchedulesGetResponse", + "SchedulesGetResponseOwner", + "SchedulesListContentType", + "SchedulesListDestination", + "SchedulesListItem", + "SchedulesListItemAlert", + "SchedulesListResponse200", + "SchedulesListScheduleType", + "SchedulesListSortDirection", + "SchedulesListSortField", + "SchedulesListStatus", + "SchedulesRecipientsGetResponse", + "SchedulesRecipientsGetResponseType", + "SchedulesRemoveRecipientsBody", + "SchedulesRemoveRecipientsResponse", + "SchedulesTransferOwnershipBody", + "ScheduleSuggestionsBody", + "ScheduleSuggestionsResponse", + "ScheduleSuggestionsResponseStatus", + "ScimGroupResponse", + "ScimGroupResponseMembersItem", + "ScimGroupsCreateBody", + "ScimGroupsCreateBodyMembersItem", + "ScimGroupsGetExcludedAttributes", + "ScimGroupsListExcludedAttributes", + "ScimGroupsListResponse", + "ScimGroupsPatchBody", + "ScimGroupsPatchBodyOperationsItemType0", + "ScimGroupsPatchBodyOperationsItemType0Op", + "ScimGroupsPatchBodyOperationsItemType0Value", + "ScimGroupsPatchBodyOperationsItemType1", + "ScimGroupsPatchBodyOperationsItemType1Op", + "ScimGroupsPatchBodyOperationsItemType2", + "ScimGroupsPatchBodyOperationsItemType2Op", + "ScimGroupsPatchBodyOperationsItemType2Path", + "ScimGroupsPatchBodyOperationsItemType2ValueItem", + "ScimGroupsPatchBodyOperationsItemType3", + "ScimGroupsPatchBodyOperationsItemType3Op", + "ScimGroupsPatchBodyOperationsItemType3Path", + "ScimGroupsPatchBodyOperationsItemType3ValueType0Item", + "ScimGroupsPatchBodySchemasItem", + "ScimGroupsReplaceBody", + "ScimGroupsReplaceBodyMembersItem", + "ScimUserCreateRequest", + "ScimUserCreateRequestUrnomniparams10UserAttribute", + "ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6", + "ScimUserPatchRequest", + "ScimUserPatchRequestOperationsItem", + "ScimUserPatchRequestOperationsItemOp", + "ScimUserPatchRequestOperationsItemValueType6", + "ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20User", + "ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6", + "ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttribute", + "ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6", + "ScimUserPatchRequestSchemasItem", + "ScimUserPutRequest", + "ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20User", + "ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6", + "ScimUserPutRequestUrnomniparams10UserAttribute", + "ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6", + "ScimUserResponse", + "ScimUsersListResponse", + "SettingsPatchExternal", + "SettingsPatchExternalCustomTextType0", + "SettingsPatchExternalRunQueriesOnType1", + "SettingsPatchExternalRunQueriesOnType2Type1", + "SettingsPatchExternalRunQueriesOnType3Type1", + "SettingsReadExternal", + "SettingsReadExternalCustomTextType0", + "SettingsReadExternalRunQueriesOnType1", + "SettingsReadExternalRunQueriesOnType2Type1", + "SettingsReadExternalRunQueriesOnType3Type1", + "StackContainer", + "SuccessResponse", + "SuggestionContextEdit", + "SuggestionEvidenceItem", + "SuggestionEvidenceItemType", + "SuggestionProposedChanges", + "SuggestionProposedChangesKind", + "Upload", + "UploadCreateBody", + "UploadCreateResponse", + "UploadDeleteResponse", + "UploadsListResponse", + "UploadsListSortDirection", + "UploadsListSortField", + "UploadsListType", + "UploadUploadedByUserType0", + "UserAttributesListResponse", + "UserAttributesListResponseRecordsItem", + "UserAttributesListResponseRecordsItemType", + "UserGroupRecipient", + "UserGroupRoleAssignmentResult", + "UserGroupRoleOrigin", + "UserGroupRoleOriginType", + "UserGroupsAssignModelRoleBody", + "UserGroupsAssignModelRoleResponse", + "UserGroupsGetModelRolesResponse", + "UsersAssignModelRoleBody", + "UsersAssignModelRoleResponse", + "UsersCreateEmailOnlyBody", + "UsersCreateEmailOnlyBodyUserAttributes", + "UsersCreateEmailOnlyBulkBody", + "UsersCreateEmailOnlyBulkBodyUsersItem", + "UsersCreateEmailOnlyBulkBodyUsersItemUserAttributes", + "UsersCreateEmailOnlyBulkResponse", + "UsersCreateEmailOnlyBulkResponseResultsItem", + "UsersCreateEmailOnlyResponse", + "UsersGetModelRolesResponse", + "UsersListEmailOnlyResponse", + "UsersListEmailOnlyResponseRecordsItem", + "UsersListEmailOnlyResponseRecordsItemUserAttributes", + "UsersListEmailOnlySortDirection", + "WhoamiModelRole", + "WhoamiModelRolePermissionsItem", + "WhoamiResponse", + "WhoamiResponseKeyScope", + "WhoamiResponseOrgRole", + "WhoamiResponseRolesByModel", + "WhoamiUser", +) diff --git a/omni_python_sdk/models/ai_agent_action.py b/omni_python_sdk/models/ai_agent_action.py new file mode 100644 index 0000000..deb7e70 --- /dev/null +++ b/omni_python_sdk/models/ai_agent_action.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.ai_agent_action_kind import AiAgentActionKind, check_ai_agent_action_kind + +T = TypeVar("T", bound="AiAgentAction") + + +@_attrs_define +class AiAgentAction: + """ + Attributes: + kind (AiAgentActionKind): Source of the entry: `sample` for `sample_queries` (model- or topic-level) and `skill` + for `skills` (model- or topic-level). Example: skill. + label (str): Short, human-readable name for the action — chip text in client UIs and the visible "prompt" on the + answer card. Example: Revenue trends. + prompt (str): Submit this string verbatim as the `prompt` on `POST /api/v1/ai/jobs`. For sample queries this is + the raw prompt; for skills it is a pre-formatted wrapper around the skill's input. Example: Skill: + Show me the recent revenue trends grouped by month…. + """ + + kind: AiAgentActionKind + label: str + prompt: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + kind: str = self.kind + + label = self.label + + prompt = self.prompt + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "kind": kind, + "label": label, + "prompt": prompt, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + kind = check_ai_agent_action_kind(d.pop("kind")) + + label = d.pop("label") + + prompt = d.pop("prompt") + + ai_agent_action = cls( + kind=kind, + label=label, + prompt=prompt, + ) + + ai_agent_action.additional_properties = d + return ai_agent_action + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_agent_action_kind.py b/omni_python_sdk/models/ai_agent_action_kind.py new file mode 100644 index 0000000..c108db3 --- /dev/null +++ b/omni_python_sdk/models/ai_agent_action_kind.py @@ -0,0 +1,14 @@ +from typing import Literal + +AiAgentActionKind = Literal["sample", "skill"] + +AI_AGENT_ACTION_KIND_VALUES: set[AiAgentActionKind] = { + "sample", + "skill", +} + + +def check_ai_agent_action_kind(value: str) -> AiAgentActionKind: + if value in AI_AGENT_ACTION_KIND_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {AI_AGENT_ACTION_KIND_VALUES!r}") diff --git a/omni_python_sdk/models/ai_agent_actions_response.py b/omni_python_sdk/models/ai_agent_actions_response.py new file mode 100644 index 0000000..49cd603 --- /dev/null +++ b/omni_python_sdk/models/ai_agent_actions_response.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.ai_agent_action import AiAgentAction + + +T = TypeVar("T", bound="AiAgentActionsResponse") + + +@_attrs_define +class AiAgentActionsResponse: + """ + Attributes: + records (list[AiAgentAction]): AI agent actions in display order: sample queries first, then skills. Topic-level + entries follow model-level ones, and skills are deduped by id with topic skills winning over model skills. + """ + + records: list[AiAgentAction] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_agent_action import AiAgentAction + + d = dict(src_dict) + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = AiAgentAction.from_dict(records_item_data) + + records.append(records_item) + + ai_agent_actions_response = cls( + records=records, + ) + + ai_agent_actions_response.additional_properties = d + return ai_agent_actions_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_branding_response.py b/omni_python_sdk/models/ai_branding_response.py new file mode 100644 index 0000000..3cf1cd7 --- /dev/null +++ b/omni_python_sdk/models/ai_branding_response.py @@ -0,0 +1,103 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiBrandingResponse") + + +@_attrs_define +class AiBrandingResponse: + """ + Attributes: + body (str): Body / description copy shown beneath the headline on AI helper landing surfaces. Example: I can + help answer data questions, build a Dashboard, or create an App.. + headline (str): Short headline shown on AI helper landing surfaces. Example: What would you like to know?. + logo_url (None | str): Absolute URL to a custom AI helper logo. `null` when the org has not configured a custom + logo — clients should render their default avatar (e.g. Blobby). Example: https://example.com/blobby.png. + name (str): Display name for the AI helper. Defaults to `Omni Agent` when no custom branding is set. Example: + Blobby. + placeholder (str): Placeholder text for the AI helper's prompt input. Example: Ask a question about your + data.... + """ + + body: str + headline: str + logo_url: None | str + name: str + placeholder: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + body = self.body + + headline = self.headline + + logo_url: None | str + logo_url = self.logo_url + + name = self.name + + placeholder = self.placeholder + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "body": body, + "headline": headline, + "logoUrl": logo_url, + "name": name, + "placeholder": placeholder, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + body = d.pop("body") + + headline = d.pop("headline") + + def _parse_logo_url(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + logo_url = _parse_logo_url(d.pop("logoUrl")) + + name = d.pop("name") + + placeholder = d.pop("placeholder") + + ai_branding_response = cls( + body=body, + headline=headline, + logo_url=logo_url, + name=name, + placeholder=placeholder, + ) + + ai_branding_response.additional_properties = d + return ai_branding_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_conversation.py b/omni_python_sdk/models/ai_conversation.py new file mode 100644 index 0000000..5fabf7c --- /dev/null +++ b/omni_python_sdk/models/ai_conversation.py @@ -0,0 +1,111 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiConversation") + + +@_attrs_define +class AiConversation: + """ + Attributes: + created_at (datetime.datetime): When the conversation was started. Example: 2025-01-15T10:00:00.000Z. + id (UUID): Conversation ID. Pass as conversationId on subsequent /api/v1/ai/jobs submissions to continue this + conversation. Example: 660e8400-e29b-41d4-a716-446655440001. + last_prompt (None | str): The most recent user prompt in this conversation, useful for displaying a one-line + summary in a list. Example: What were our top products last week?. + name (None | str): Conversation title. Set by the AI after the first turn; null on brand-new sessions. Example: + Top products last week. + updated_at (datetime.datetime): When the conversation was last touched (most recent prompt or AI activity). + Example: 2025-01-15T10:01:30.000Z. + """ + + created_at: datetime.datetime + id: UUID + last_prompt: None | str + name: None | str + updated_at: datetime.datetime + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created_at = self.created_at.isoformat() + + id = str(self.id) + + last_prompt: None | str + last_prompt = self.last_prompt + + name: None | str + name = self.name + + updated_at = self.updated_at.isoformat() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "createdAt": created_at, + "id": id, + "lastPrompt": last_prompt, + "name": name, + "updatedAt": updated_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + created_at = datetime.datetime.fromisoformat(d.pop("createdAt")) + + id = UUID(d.pop("id")) + + def _parse_last_prompt(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + last_prompt = _parse_last_prompt(d.pop("lastPrompt")) + + def _parse_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + name = _parse_name(d.pop("name")) + + updated_at = datetime.datetime.fromisoformat(d.pop("updatedAt")) + + ai_conversation = cls( + created_at=created_at, + id=id, + last_prompt=last_prompt, + name=name, + updated_at=updated_at, + ) + + ai_conversation.additional_properties = d + return ai_conversation + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_conversation_detail_response.py b/omni_python_sdk/models/ai_conversation_detail_response.py new file mode 100644 index 0000000..d7c257f --- /dev/null +++ b/omni_python_sdk/models/ai_conversation_detail_response.py @@ -0,0 +1,115 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.ai_conversation_message import AiConversationMessage + + +T = TypeVar("T", bound="AiConversationDetailResponse") + + +@_attrs_define +class AiConversationDetailResponse: + """ + Attributes: + created_at (datetime.datetime): + id (UUID): + messages (list[AiConversationMessage]): Messages in chronological order. Alternating user / assistant turns. + name (None | str): + updated_at (datetime.datetime): + """ + + created_at: datetime.datetime + id: UUID + messages: list[AiConversationMessage] + name: None | str + updated_at: datetime.datetime + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created_at = self.created_at.isoformat() + + id = str(self.id) + + messages = [] + for messages_item_data in self.messages: + messages_item = messages_item_data.to_dict() + messages.append(messages_item) + + name: None | str + name = self.name + + updated_at = self.updated_at.isoformat() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "createdAt": created_at, + "id": id, + "messages": messages, + "name": name, + "updatedAt": updated_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_conversation_message import AiConversationMessage + + d = dict(src_dict) + created_at = datetime.datetime.fromisoformat(d.pop("createdAt")) + + id = UUID(d.pop("id")) + + messages = [] + _messages = d.pop("messages") + for messages_item_data in _messages: + messages_item = AiConversationMessage.from_dict(messages_item_data) + + messages.append(messages_item) + + def _parse_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + name = _parse_name(d.pop("name")) + + updated_at = datetime.datetime.fromisoformat(d.pop("updatedAt")) + + ai_conversation_detail_response = cls( + created_at=created_at, + id=id, + messages=messages, + name=name, + updated_at=updated_at, + ) + + ai_conversation_detail_response.additional_properties = d + return ai_conversation_detail_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_conversation_message.py b/omni_python_sdk/models/ai_conversation_message.py new file mode 100644 index 0000000..919ed9d --- /dev/null +++ b/omni_python_sdk/models/ai_conversation_message.py @@ -0,0 +1,126 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.ai_conversation_message_role import AiConversationMessageRole, check_ai_conversation_message_role + +T = TypeVar("T", bound="AiConversationMessage") + + +@_attrs_define +class AiConversationMessage: + """ + Attributes: + created_at (datetime.datetime): When this turn was recorded. Example: 2025-01-15T10:00:00.000Z. + job_id (None | UUID): The agentic job that produced this assistant turn. Only set for assistant messages — + clients use it to fetch the rendered chart via GET /api/v1/ai/jobs/{jobId}/vis. Null when the turn predates jobs + or when we could not associate one. Example: 550e8400-e29b-41d4-a716-446655440000. + omni_chat_url (None | str): Deep link to the assistant turn in the Omni chat UI. Null for user turns, and for + assistant turns produced outside the Agentic API (where no AgenticJob row exists). Example: https://my- + org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001. + role (AiConversationMessageRole): Speaker — `user` for prompts the user submitted, `assistant` for Blobby's + responses. Example: user. + text (str): Markdown content of the message. For assistant turns this is the same string returned by + /api/v1/ai/jobs/{jobId}/result#message. Example: What were our top products last week?. + """ + + created_at: datetime.datetime + job_id: None | UUID + omni_chat_url: None | str + role: AiConversationMessageRole + text: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created_at = self.created_at.isoformat() + + job_id: None | str + if isinstance(self.job_id, UUID): + job_id = str(self.job_id) + else: + job_id = self.job_id + + omni_chat_url: None | str + omni_chat_url = self.omni_chat_url + + role: str = self.role + + text = self.text + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "createdAt": created_at, + "jobId": job_id, + "omniChatUrl": omni_chat_url, + "role": role, + "text": text, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + created_at = datetime.datetime.fromisoformat(d.pop("createdAt")) + + def _parse_job_id(data: object) -> None | UUID: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + job_id_type_0 = UUID(data) + + return job_id_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UUID, data) + + job_id = _parse_job_id(d.pop("jobId")) + + def _parse_omni_chat_url(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + omni_chat_url = _parse_omni_chat_url(d.pop("omniChatUrl")) + + role = check_ai_conversation_message_role(d.pop("role")) + + text = d.pop("text") + + ai_conversation_message = cls( + created_at=created_at, + job_id=job_id, + omni_chat_url=omni_chat_url, + role=role, + text=text, + ) + + ai_conversation_message.additional_properties = d + return ai_conversation_message + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_conversation_message_role.py b/omni_python_sdk/models/ai_conversation_message_role.py new file mode 100644 index 0000000..f4eed3d --- /dev/null +++ b/omni_python_sdk/models/ai_conversation_message_role.py @@ -0,0 +1,14 @@ +from typing import Literal + +AiConversationMessageRole = Literal["assistant", "user"] + +AI_CONVERSATION_MESSAGE_ROLE_VALUES: set[AiConversationMessageRole] = { + "assistant", + "user", +} + + +def check_ai_conversation_message_role(value: str) -> AiConversationMessageRole: + if value in AI_CONVERSATION_MESSAGE_ROLE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {AI_CONVERSATION_MESSAGE_ROLE_VALUES!r}") diff --git a/omni_python_sdk/models/ai_conversations_list_response.py b/omni_python_sdk/models/ai_conversations_list_response.py new file mode 100644 index 0000000..7522ae3 --- /dev/null +++ b/omni_python_sdk/models/ai_conversations_list_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.ai_conversation import AiConversation + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="AiConversationsListResponse") + + +@_attrs_define +class AiConversationsListResponse: + """ + Attributes: + page_info (PageInfo): + records (list[AiConversation]): Conversations ordered by updatedAt descending. + """ + + page_info: PageInfo + records: list[AiConversation] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_conversation import AiConversation + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = AiConversation.from_dict(records_item_data) + + records.append(records_item) + + ai_conversations_list_response = cls( + page_info=page_info, + records=records, + ) + + ai_conversations_list_response.additional_properties = d + return ai_conversations_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_credit_controls_response.py b/omni_python_sdk/models/ai_credit_controls_response.py new file mode 100644 index 0000000..4db93ab --- /dev/null +++ b/omni_python_sdk/models/ai_credit_controls_response.py @@ -0,0 +1,129 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiCreditControlsResponse") + + +@_attrs_define +class AiCreditControlsResponse: + """ + Attributes: + account_credit_limit (float): Monthly AI credit limit for the whole Omni account (shared across every org under + the same Salesforce account), not just this org. 0 when no limit is configured. Example: 2000. + credits_used (float): This org's credit usage in the current billing period. Example: 450. + downgrade_credits (float | None): Downgrade threshold, or `null` if the downgrade control is off. Example: 800. + period_end (int): End of the current billing period as a Unix ms timestamp (UTC calendar-month boundary). + period_start (int): Start of the current billing period as a Unix ms timestamp (UTC calendar-month boundary). + shutoff_credits (float | None): Shutoff threshold, or `null` if the shutoff control is off. Example: 1200. + user_default_credits (float | None): Default per-user AI credit limit, or `null` when users are unlimited by + default. Example: 100. + """ + + account_credit_limit: float + credits_used: float + downgrade_credits: float | None + period_end: int + period_start: int + shutoff_credits: float | None + user_default_credits: float | None + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + account_credit_limit = self.account_credit_limit + + credits_used = self.credits_used + + downgrade_credits: float | None + downgrade_credits = self.downgrade_credits + + period_end = self.period_end + + period_start = self.period_start + + shutoff_credits: float | None + shutoff_credits = self.shutoff_credits + + user_default_credits: float | None + user_default_credits = self.user_default_credits + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "accountCreditLimit": account_credit_limit, + "creditsUsed": credits_used, + "downgradeCredits": downgrade_credits, + "periodEnd": period_end, + "periodStart": period_start, + "shutoffCredits": shutoff_credits, + "userDefaultCredits": user_default_credits, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + account_credit_limit = d.pop("accountCreditLimit") + + credits_used = d.pop("creditsUsed") + + def _parse_downgrade_credits(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + downgrade_credits = _parse_downgrade_credits(d.pop("downgradeCredits")) + + period_end = d.pop("periodEnd") + + period_start = d.pop("periodStart") + + def _parse_shutoff_credits(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + shutoff_credits = _parse_shutoff_credits(d.pop("shutoffCredits")) + + def _parse_user_default_credits(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + user_default_credits = _parse_user_default_credits(d.pop("userDefaultCredits")) + + ai_credit_controls_response = cls( + account_credit_limit=account_credit_limit, + credits_used=credits_used, + downgrade_credits=downgrade_credits, + period_end=period_end, + period_start=period_start, + shutoff_credits=shutoff_credits, + user_default_credits=user_default_credits, + ) + + ai_credit_controls_response.additional_properties = d + return ai_credit_controls_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_credit_controls_update_body.py b/omni_python_sdk/models/ai_credit_controls_update_body.py new file mode 100644 index 0000000..bd78656 --- /dev/null +++ b/omni_python_sdk/models/ai_credit_controls_update_body.py @@ -0,0 +1,99 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="AiCreditControlsUpdateBody") + + +@_attrs_define +class AiCreditControlsUpdateBody: + """ + Attributes: + downgrade_credits (float | None | Unset): Credit usage at which AI downgrades to a cheaper model. Omit to leave + unchanged, `null` to turn off, or a non-negative number to set. Must be at or below shutoffCredits. Example: + 800. + shutoff_credits (float | None | Unset): Credit usage at which AI shuts off entirely. Omit to leave unchanged, + `null` to turn off, or a non-negative number to set. Example: 1200. + user_default_credits (float | None | Unset): Default per-user AI credit limit for the billing period — what + every user without an individual limit gets. Omit to leave unchanged, `null` for unlimited by default, or a non- + negative number to set. Example: 100. + """ + + downgrade_credits: float | None | Unset = UNSET + shutoff_credits: float | None | Unset = UNSET + user_default_credits: float | None | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + downgrade_credits: float | None | Unset + if isinstance(self.downgrade_credits, Unset): + downgrade_credits = UNSET + else: + downgrade_credits = self.downgrade_credits + + shutoff_credits: float | None | Unset + if isinstance(self.shutoff_credits, Unset): + shutoff_credits = UNSET + else: + shutoff_credits = self.shutoff_credits + + user_default_credits: float | None | Unset + if isinstance(self.user_default_credits, Unset): + user_default_credits = UNSET + else: + user_default_credits = self.user_default_credits + + field_dict: dict[str, Any] = {} + + field_dict.update({}) + if downgrade_credits is not UNSET: + field_dict["downgradeCredits"] = downgrade_credits + if shutoff_credits is not UNSET: + field_dict["shutoffCredits"] = shutoff_credits + if user_default_credits is not UNSET: + field_dict["userDefaultCredits"] = user_default_credits + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_downgrade_credits(data: object) -> float | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(float | None | Unset, data) + + downgrade_credits = _parse_downgrade_credits(d.pop("downgradeCredits", UNSET)) + + def _parse_shutoff_credits(data: object) -> float | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(float | None | Unset, data) + + shutoff_credits = _parse_shutoff_credits(d.pop("shutoffCredits", UNSET)) + + def _parse_user_default_credits(data: object) -> float | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(float | None | Unset, data) + + user_default_credits = _parse_user_default_credits(d.pop("userDefaultCredits", UNSET)) + + ai_credit_controls_update_body = cls( + downgrade_credits=downgrade_credits, + shutoff_credits=shutoff_credits, + user_default_credits=user_default_credits, + ) + + return ai_credit_controls_update_body diff --git a/omni_python_sdk/models/ai_credit_controls_users_list_response.py b/omni_python_sdk/models/ai_credit_controls_users_list_response.py new file mode 100644 index 0000000..2720f36 --- /dev/null +++ b/omni_python_sdk/models/ai_credit_controls_users_list_response.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.ai_credit_controls_users_list_response_records_item import ( + AiCreditControlsUsersListResponseRecordsItem, + ) + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="AiCreditControlsUsersListResponse") + + +@_attrs_define +class AiCreditControlsUsersListResponse: + """ + Attributes: + page_info (PageInfo): + records (list[AiCreditControlsUsersListResponseRecordsItem]): Users with an individual AI credit limit, ordered + by userId ascending. + """ + + page_info: PageInfo + records: list[AiCreditControlsUsersListResponseRecordsItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_credit_controls_users_list_response_records_item import ( + AiCreditControlsUsersListResponseRecordsItem, + ) + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = AiCreditControlsUsersListResponseRecordsItem.from_dict(records_item_data) + + records.append(records_item) + + ai_credit_controls_users_list_response = cls( + page_info=page_info, + records=records, + ) + + ai_credit_controls_users_list_response.additional_properties = d + return ai_credit_controls_users_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_credit_controls_users_list_response_records_item.py b/omni_python_sdk/models/ai_credit_controls_users_list_response_records_item.py new file mode 100644 index 0000000..4a5f471 --- /dev/null +++ b/omni_python_sdk/models/ai_credit_controls_users_list_response_records_item.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiCreditControlsUsersListResponseRecordsItem") + + +@_attrs_define +class AiCreditControlsUsersListResponseRecordsItem: + """ + Attributes: + credit_limit (float | None): The user's individual AI credit limit, or `null` for an explicit unlimited + override. Example: 50. + user_id (str): The user's id within this organization. Example: f4a2b3c8-0d1e-4f5a-9b6c-7d8e9f0a1b2c. + """ + + credit_limit: float | None + user_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + credit_limit: float | None + credit_limit = self.credit_limit + + user_id = self.user_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "creditLimit": credit_limit, + "userId": user_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_credit_limit(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + credit_limit = _parse_credit_limit(d.pop("creditLimit")) + + user_id = d.pop("userId") + + ai_credit_controls_users_list_response_records_item = cls( + credit_limit=credit_limit, + user_id=user_id, + ) + + ai_credit_controls_users_list_response_records_item.additional_properties = d + return ai_credit_controls_users_list_response_records_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_credit_shutoff_error.py b/omni_python_sdk/models/ai_credit_shutoff_error.py new file mode 100644 index 0000000..2a65062 --- /dev/null +++ b/omni_python_sdk/models/ai_credit_shutoff_error.py @@ -0,0 +1,80 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.ai_credit_shutoff_error_code import AiCreditShutoffErrorCode, check_ai_credit_shutoff_error_code + +T = TypeVar("T", bound="AiCreditShutoffError") + + +@_attrs_define +class AiCreditShutoffError: + """ + Attributes: + code (AiCreditShutoffErrorCode): Stable reason code identifying an AI-credit shutoff. Example: shutoff. + detail (str): Human-readable error message describing what went wrong. Example: The AI credit limit has been + reached. Contact your administrator for assistance.. + status (int): HTTP status code of the error. Example: 402. + """ + + code: AiCreditShutoffErrorCode + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + code: str = self.code + + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "code": code, + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + code = check_ai_credit_shutoff_error_code(d.pop("code")) + + detail = d.pop("detail") + + status = d.pop("status") + + ai_credit_shutoff_error = cls( + code=code, + detail=detail, + status=status, + ) + + ai_credit_shutoff_error.additional_properties = d + return ai_credit_shutoff_error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_credit_shutoff_error_code.py b/omni_python_sdk/models/ai_credit_shutoff_error_code.py new file mode 100644 index 0000000..d7231fe --- /dev/null +++ b/omni_python_sdk/models/ai_credit_shutoff_error_code.py @@ -0,0 +1,13 @@ +from typing import Literal + +AiCreditShutoffErrorCode = Literal["shutoff"] + +AI_CREDIT_SHUTOFF_ERROR_CODE_VALUES: set[AiCreditShutoffErrorCode] = { + "shutoff", +} + + +def check_ai_credit_shutoff_error_code(value: str) -> AiCreditShutoffErrorCode: + if value in AI_CREDIT_SHUTOFF_ERROR_CODE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {AI_CREDIT_SHUTOFF_ERROR_CODE_VALUES!r}") diff --git a/omni_python_sdk/models/ai_eval_prompt_sets_list_archived.py b/omni_python_sdk/models/ai_eval_prompt_sets_list_archived.py new file mode 100644 index 0000000..eaa5d23 --- /dev/null +++ b/omni_python_sdk/models/ai_eval_prompt_sets_list_archived.py @@ -0,0 +1,14 @@ +from typing import Literal + +AiEvalPromptSetsListArchived = Literal["false", "true"] + +AI_EVAL_PROMPT_SETS_LIST_ARCHIVED_VALUES: set[AiEvalPromptSetsListArchived] = { + "false", + "true", +} + + +def check_ai_eval_prompt_sets_list_archived(value: str) -> AiEvalPromptSetsListArchived: + if value in AI_EVAL_PROMPT_SETS_LIST_ARCHIVED_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {AI_EVAL_PROMPT_SETS_LIST_ARCHIVED_VALUES!r}") diff --git a/omni_python_sdk/models/ai_eval_runs_list_archived.py b/omni_python_sdk/models/ai_eval_runs_list_archived.py new file mode 100644 index 0000000..7e1a678 --- /dev/null +++ b/omni_python_sdk/models/ai_eval_runs_list_archived.py @@ -0,0 +1,14 @@ +from typing import Literal + +AiEvalRunsListArchived = Literal["false", "true"] + +AI_EVAL_RUNS_LIST_ARCHIVED_VALUES: set[AiEvalRunsListArchived] = { + "false", + "true", +} + + +def check_ai_eval_runs_list_archived(value: str) -> AiEvalRunsListArchived: + if value in AI_EVAL_RUNS_LIST_ARCHIVED_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {AI_EVAL_RUNS_LIST_ARCHIVED_VALUES!r}") diff --git a/omni_python_sdk/models/ai_generate_query_body.py b/omni_python_sdk/models/ai_generate_query_body.py new file mode 100644 index 0000000..95de7f4 --- /dev/null +++ b/omni_python_sdk/models/ai_generate_query_body.py @@ -0,0 +1,149 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="AiGenerateQueryBody") + + +@_attrs_define +class AiGenerateQueryBody: + """ + Attributes: + model_id (UUID): The UUID of the shared model to query against. Only shared models are supported. Example: + 770e8400-e29b-41d4-a716-446655440002. + prompt (str): The natural language prompt describing the data you want to retrieve. Example: Show me total + revenue by month for the last year. + branch_id (UUID | Unset): Optional branch ID for the model. Must be a branch of the shared model specified by + modelId. Example: 550e8400-e29b-41d4-a716-446655440000. + current_topic_name (str | Unset): The name of the current topic to scope query generation. If not provided, AI + will automatically select the best topic for your prompt. Example: order_items. + query_all_views (bool | Unset): If true and the model has query_all_views_and_fields enabled, AI can query views + not in any topic. + run_query (bool | Unset): Whether to execute the generated query and return results. Defaults to true. Set to + false to only generate the query definition without executing it. Example: True. + user_id (UUID | Unset): User ID to execute the query as. Their permissions will be applied for row-level + security. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated + user. Example: 990e8400-e29b-41d4-a716-446655440004. + workbook_url (bool | Unset): If true, creates a new workbook with the generated query and returns its URL. + Useful for sharing results or further exploration. + """ + + model_id: UUID + prompt: str + branch_id: UUID | Unset = UNSET + current_topic_name: str | Unset = UNSET + query_all_views: bool | Unset = UNSET + run_query: bool | Unset = UNSET + user_id: UUID | Unset = UNSET + workbook_url: bool | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + model_id = str(self.model_id) + + prompt = self.prompt + + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + current_topic_name = self.current_topic_name + + query_all_views = self.query_all_views + + run_query = self.run_query + + user_id: str | Unset = UNSET + if not isinstance(self.user_id, Unset): + user_id = str(self.user_id) + + workbook_url = self.workbook_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "modelId": model_id, + "prompt": prompt, + } + ) + if branch_id is not UNSET: + field_dict["branchId"] = branch_id + if current_topic_name is not UNSET: + field_dict["currentTopicName"] = current_topic_name + if query_all_views is not UNSET: + field_dict["queryAllViews"] = query_all_views + if run_query is not UNSET: + field_dict["runQuery"] = run_query + if user_id is not UNSET: + field_dict["userId"] = user_id + if workbook_url is not UNSET: + field_dict["workbookUrl"] = workbook_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + model_id = UUID(d.pop("modelId")) + + prompt = d.pop("prompt") + + _branch_id = d.pop("branchId", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + current_topic_name = d.pop("currentTopicName", UNSET) + + query_all_views = d.pop("queryAllViews", UNSET) + + run_query = d.pop("runQuery", UNSET) + + _user_id = d.pop("userId", UNSET) + user_id: UUID | Unset + if isinstance(_user_id, Unset): + user_id = UNSET + else: + user_id = UUID(_user_id) + + workbook_url = d.pop("workbookUrl", UNSET) + + ai_generate_query_body = cls( + model_id=model_id, + prompt=prompt, + branch_id=branch_id, + current_topic_name=current_topic_name, + query_all_views=query_all_views, + run_query=run_query, + user_id=user_id, + workbook_url=workbook_url, + ) + + ai_generate_query_body.additional_properties = d + return ai_generate_query_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_generate_query_response.py b/omni_python_sdk/models/ai_generate_query_response.py new file mode 100644 index 0000000..eb4eb3e --- /dev/null +++ b/omni_python_sdk/models/ai_generate_query_response.py @@ -0,0 +1,184 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.ai_generate_query_response_error_type_0 import AiGenerateQueryResponseErrorType0 + from ..models.ai_generate_query_response_result import AiGenerateQueryResponseResult + from ..models.ai_semantic_query import AiSemanticQuery + + +T = TypeVar("T", bound="AiGenerateQueryResponse") + + +@_attrs_define +class AiGenerateQueryResponse: + """ + Attributes: + error (AiGenerateQueryResponseErrorType0 | None): Error details if query generation failed. Null on success. + query (AiSemanticQuery): The generated semantic query definition. Null if generation failed. This query can be + passed directly to the POST /api/v1/query/run endpoint. (Not statically modeled; use plain dicts.) + base_view (None | str | Unset): The base view name used for query generation when queryAllViews surfaced a non- + topic view. Mutually exclusive with `topic` — exactly one is non-null when a query was generated. + downgraded_model_tier (str | Unset): Present only when the organization is over its AI downgrade threshold, + signaling the query was generated on a downgraded (cheaper) model tier (e.g. 'haiku') to conserve credits. + Advisory and best-effort — the call still succeeds, and clients may surface that a downgraded model was used. + Absent when no downgrade applied. Example: haiku. + result (AiGenerateQueryResponseResult | Unset): Query execution results as a JSON object. Only present when + runQuery is true (the default) and the query executed successfully. The structure contains the query result + data. + topic (None | str | Unset): The topic name used for query generation. Mutually exclusive with `baseView` — + exactly one is non-null when a query was generated. Example: order_items. + workbook_url (str | Unset): URL to view and edit the generated query in an Omni workbook. Only present when + workbookUrl was set to true in the request. Example: https://myorg.omni.co/w/abc123/1. + """ + + error: AiGenerateQueryResponseErrorType0 | None + query: AiSemanticQuery + base_view: None | str | Unset = UNSET + downgraded_model_tier: str | Unset = UNSET + result: AiGenerateQueryResponseResult | Unset = UNSET + topic: None | str | Unset = UNSET + workbook_url: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.ai_generate_query_response_error_type_0 import AiGenerateQueryResponseErrorType0 + + error: dict[str, Any] | None + if isinstance(self.error, AiGenerateQueryResponseErrorType0): + error = self.error.to_dict() + else: + error = self.error + + query = self.query.to_dict() + + base_view: None | str | Unset + if isinstance(self.base_view, Unset): + base_view = UNSET + else: + base_view = self.base_view + + downgraded_model_tier = self.downgraded_model_tier + + result: dict[str, Any] | Unset = UNSET + if not isinstance(self.result, Unset): + result = self.result.to_dict() + + topic: None | str | Unset + if isinstance(self.topic, Unset): + topic = UNSET + else: + topic = self.topic + + workbook_url = self.workbook_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "error": error, + "query": query, + } + ) + if base_view is not UNSET: + field_dict["baseView"] = base_view + if downgraded_model_tier is not UNSET: + field_dict["downgradedModelTier"] = downgraded_model_tier + if result is not UNSET: + field_dict["result"] = result + if topic is not UNSET: + field_dict["topic"] = topic + if workbook_url is not UNSET: + field_dict["workbookUrl"] = workbook_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_generate_query_response_error_type_0 import AiGenerateQueryResponseErrorType0 + from ..models.ai_generate_query_response_result import AiGenerateQueryResponseResult + from ..models.ai_semantic_query import AiSemanticQuery + + d = dict(src_dict) + + def _parse_error(data: object) -> AiGenerateQueryResponseErrorType0 | None: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + error_type_0 = AiGenerateQueryResponseErrorType0.from_dict(data) + + return error_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(AiGenerateQueryResponseErrorType0 | None, data) + + error = _parse_error(d.pop("error")) + + query = AiSemanticQuery.from_dict(d.pop("query")) + + def _parse_base_view(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + base_view = _parse_base_view(d.pop("baseView", UNSET)) + + downgraded_model_tier = d.pop("downgradedModelTier", UNSET) + + _result = d.pop("result", UNSET) + result: AiGenerateQueryResponseResult | Unset + if isinstance(_result, Unset): + result = UNSET + else: + result = AiGenerateQueryResponseResult.from_dict(_result) + + def _parse_topic(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + topic = _parse_topic(d.pop("topic", UNSET)) + + workbook_url = d.pop("workbookUrl", UNSET) + + ai_generate_query_response = cls( + error=error, + query=query, + base_view=base_view, + downgraded_model_tier=downgraded_model_tier, + result=result, + topic=topic, + workbook_url=workbook_url, + ) + + ai_generate_query_response.additional_properties = d + return ai_generate_query_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_generate_query_response_error_type_0.py b/omni_python_sdk/models/ai_generate_query_response_error_type_0.py new file mode 100644 index 0000000..c67a9cd --- /dev/null +++ b/omni_python_sdk/models/ai_generate_query_response_error_type_0.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiGenerateQueryResponseErrorType0") + + +@_attrs_define +class AiGenerateQueryResponseErrorType0: + """Error details if query generation failed. Null on success. + + Attributes: + detail (str): Detailed error message explaining why query generation failed. Example: The AI was unable to + generate a query for this prompt. Try rephrasing your question to be more specific about the data you want to + retrieve.. + message (str): Short error summary. Example: No query generated. + """ + + detail: str + message: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + message = self.message + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "message": message, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + message = d.pop("message") + + ai_generate_query_response_error_type_0 = cls( + detail=detail, + message=message, + ) + + ai_generate_query_response_error_type_0.additional_properties = d + return ai_generate_query_response_error_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_generate_query_response_result.py b/omni_python_sdk/models/ai_generate_query_response_result.py new file mode 100644 index 0000000..9a1b564 --- /dev/null +++ b/omni_python_sdk/models/ai_generate_query_response_result.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiGenerateQueryResponseResult") + + +@_attrs_define +class AiGenerateQueryResponseResult: + """Query execution results as a JSON object. Only present when runQuery is true (the default) and the query executed + successfully. The structure contains the query result data. + + """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + ai_generate_query_response_result = cls() + + ai_generate_query_response_result.additional_properties = d + return ai_generate_query_response_result + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_job_action.py b/omni_python_sdk/models/ai_job_action.py new file mode 100644 index 0000000..588dacc --- /dev/null +++ b/omni_python_sdk/models/ai_job_action.py @@ -0,0 +1,103 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.ai_job_action_query_result import AiJobActionQueryResult + + +T = TypeVar("T", bound="AiJobAction") + + +@_attrs_define +class AiJobAction: + """ + Attributes: + message (str): The AI's explanation of what it is doing in this step, written in natural language. Example: I'll + generate a query to find the top 5 products by total revenue.. + timestamp (str): ISO 8601 timestamp when this action occurred. Example: 2025-01-15T10:00:10.000Z. + type_ (str): The type of action. Common types include "generate_query" (query generation and execution) and + "summarize" (final answer synthesis). Example: generate_query. + result (AiJobActionQueryResult | Unset): Query result data. Only present for generate_query action types. + """ + + message: str + timestamp: str + type_: str + result: AiJobActionQueryResult | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + timestamp = self.timestamp + + type_ = self.type_ + + result: dict[str, Any] | Unset = UNSET + if not isinstance(self.result, Unset): + result = self.result.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + "timestamp": timestamp, + "type": type_, + } + ) + if result is not UNSET: + field_dict["result"] = result + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_job_action_query_result import AiJobActionQueryResult + + d = dict(src_dict) + message = d.pop("message") + + timestamp = d.pop("timestamp") + + type_ = d.pop("type") + + _result = d.pop("result", UNSET) + result: AiJobActionQueryResult | Unset + if isinstance(_result, Unset): + result = UNSET + else: + result = AiJobActionQueryResult.from_dict(_result) + + ai_job_action = cls( + message=message, + timestamp=timestamp, + type_=type_, + result=result, + ) + + ai_job_action.additional_properties = d + return ai_job_action + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_job_action_query_result.py b/omni_python_sdk/models/ai_job_action_query_result.py new file mode 100644 index 0000000..c24729a --- /dev/null +++ b/omni_python_sdk/models/ai_job_action_query_result.py @@ -0,0 +1,137 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.ai_job_action_query_result_status import ( + AiJobActionQueryResultStatus, + check_ai_job_action_query_result_status, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.ai_job_action_query_result_query import AiJobActionQueryResultQuery + + +T = TypeVar("T", bound="AiJobActionQueryResult") + + +@_attrs_define +class AiJobActionQueryResult: + """Query result data. Only present for generate_query action types. + + Attributes: + csv_result (str): Query results formatted as CSV text. Example: Name,Total Revenue + Ray-Ban Sunglasses,"678,994.41" + Levi's 501 Jeans,"475,072.00". + csv_result_was_truncated (bool): Whether the CSV data was truncated due to size limits. If true, the full result + set may contain additional rows not included in csvResult. + has_results (bool): Whether the query returned any data rows. Example: True. + query (AiJobActionQueryResultQuery): The semantic query definition that was executed. This can be used with the + POST /api/v1/query/run endpoint to re-run the query. + query_name (str): Human-readable name describing what this query retrieves. Example: Top 5 Products by Revenue. + status (AiJobActionQueryResultStatus): Whether the query executed successfully. Example: success. + total_row_count (int): Total number of rows returned by the query. Example: 5. + result_id (str | Unset): Stable, unique identifier for this query result within the job. Use it to reference a + specific result — for example, to correlate or de-duplicate results across responses. Example: + 928c5838-000d-4943-b305-f6242c1b4922. + """ + + csv_result: str + csv_result_was_truncated: bool + has_results: bool + query: AiJobActionQueryResultQuery + query_name: str + status: AiJobActionQueryResultStatus + total_row_count: int + result_id: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + csv_result = self.csv_result + + csv_result_was_truncated = self.csv_result_was_truncated + + has_results = self.has_results + + query = self.query.to_dict() + + query_name = self.query_name + + status: str = self.status + + total_row_count = self.total_row_count + + result_id = self.result_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "csvResult": csv_result, + "csvResultWasTruncated": csv_result_was_truncated, + "hasResults": has_results, + "query": query, + "queryName": query_name, + "status": status, + "totalRowCount": total_row_count, + } + ) + if result_id is not UNSET: + field_dict["resultId"] = result_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_job_action_query_result_query import AiJobActionQueryResultQuery + + d = dict(src_dict) + csv_result = d.pop("csvResult") + + csv_result_was_truncated = d.pop("csvResultWasTruncated") + + has_results = d.pop("hasResults") + + query = AiJobActionQueryResultQuery.from_dict(d.pop("query")) + + query_name = d.pop("queryName") + + status = check_ai_job_action_query_result_status(d.pop("status")) + + total_row_count = d.pop("totalRowCount") + + result_id = d.pop("resultId", UNSET) + + ai_job_action_query_result = cls( + csv_result=csv_result, + csv_result_was_truncated=csv_result_was_truncated, + has_results=has_results, + query=query, + query_name=query_name, + status=status, + total_row_count=total_row_count, + result_id=result_id, + ) + + ai_job_action_query_result.additional_properties = d + return ai_job_action_query_result + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_job_action_query_result_query.py b/omni_python_sdk/models/ai_job_action_query_result_query.py new file mode 100644 index 0000000..2945cca --- /dev/null +++ b/omni_python_sdk/models/ai_job_action_query_result_query.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiJobActionQueryResultQuery") + + +@_attrs_define +class AiJobActionQueryResultQuery: + """The semantic query definition that was executed. This can be used with the POST /api/v1/query/run endpoint to re-run + the query. + + """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + ai_job_action_query_result_query = cls() + + ai_job_action_query_result_query.additional_properties = d + return ai_job_action_query_result_query + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_job_action_query_result_status.py b/omni_python_sdk/models/ai_job_action_query_result_status.py new file mode 100644 index 0000000..a6d613d --- /dev/null +++ b/omni_python_sdk/models/ai_job_action_query_result_status.py @@ -0,0 +1,14 @@ +from typing import Literal + +AiJobActionQueryResultStatus = Literal["error", "success"] + +AI_JOB_ACTION_QUERY_RESULT_STATUS_VALUES: set[AiJobActionQueryResultStatus] = { + "error", + "success", +} + + +def check_ai_job_action_query_result_status(value: str) -> AiJobActionQueryResultStatus: + if value in AI_JOB_ACTION_QUERY_RESULT_STATUS_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {AI_JOB_ACTION_QUERY_RESULT_STATUS_VALUES!r}") diff --git a/omni_python_sdk/models/ai_job_cancel_response.py b/omni_python_sdk/models/ai_job_cancel_response.py new file mode 100644 index 0000000..de64276 --- /dev/null +++ b/omni_python_sdk/models/ai_job_cancel_response.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.ai_job_cancel_response_state import AiJobCancelResponseState, check_ai_job_cancel_response_state + +T = TypeVar("T", bound="AiJobCancelResponse") + + +@_attrs_define +class AiJobCancelResponse: + """ + Attributes: + job_id (UUID): The job ID that was requested to cancel. Example: 550e8400-e29b-41d4-a716-446655440000. + state (AiJobCancelResponseState): The job state after the cancellation attempt. CANCELLED if the cancellation + was successful. If the job was already in a terminal state (COMPLETE, FAILED, CANCELLED), the current state is + returned unchanged — the endpoint is idempotent. Example: CANCELLED. + """ + + job_id: UUID + state: AiJobCancelResponseState + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + job_id = str(self.job_id) + + state: str = self.state + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "jobId": job_id, + "state": state, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + job_id = UUID(d.pop("jobId")) + + state = check_ai_job_cancel_response_state(d.pop("state")) + + ai_job_cancel_response = cls( + job_id=job_id, + state=state, + ) + + ai_job_cancel_response.additional_properties = d + return ai_job_cancel_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_job_cancel_response_state.py b/omni_python_sdk/models/ai_job_cancel_response_state.py new file mode 100644 index 0000000..f107004 --- /dev/null +++ b/omni_python_sdk/models/ai_job_cancel_response_state.py @@ -0,0 +1,18 @@ +from typing import Literal + +AiJobCancelResponseState = Literal["CANCELLED", "COMPLETE", "DELIVERING", "EXECUTING", "FAILED", "QUEUED"] + +AI_JOB_CANCEL_RESPONSE_STATE_VALUES: set[AiJobCancelResponseState] = { + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED", +} + + +def check_ai_job_cancel_response_state(value: str) -> AiJobCancelResponseState: + if value in AI_JOB_CANCEL_RESPONSE_STATE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {AI_JOB_CANCEL_RESPONSE_STATE_VALUES!r}") diff --git a/omni_python_sdk/models/ai_job_result_response.py b/omni_python_sdk/models/ai_job_result_response.py new file mode 100644 index 0000000..1014bbf --- /dev/null +++ b/omni_python_sdk/models/ai_job_result_response.py @@ -0,0 +1,126 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.ai_job_action import AiJobAction + + +T = TypeVar("T", bound="AiJobResultResponse") + + +@_attrs_define +class AiJobResultResponse: + """ + Attributes: + actions (list[AiJobAction] | Unset): Ordered list of actions the AI took during execution. Each action + represents a step such as generating a query, executing it, or synthesizing a final answer. + message (str | Unset): The AI's final response message in Markdown format. This is the complete answer to the + original prompt, incorporating data from all executed queries. Example: ### Top 5 Products by Revenue + + 1. **Sunglasses** - $678,994 + 2. **Jeans** - $475,072. + omni_chat_url (str | Unset): URL to view this conversation in the Omni chat interface. Opens the chat session + where the job actions and results are visible. Example: https://my- + org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001. + result_summary (str | Unset): Summary of the job result. Typically matches the final message content. Example: + ### Top 5 Products by Revenue + + 1. **Sunglasses** - $678,994 + 2. **Jeans** - $475,072. + topic (str | Unset): The topic name used for query generation. Example: order_items. + """ + + actions: list[AiJobAction] | Unset = UNSET + message: str | Unset = UNSET + omni_chat_url: str | Unset = UNSET + result_summary: str | Unset = UNSET + topic: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + actions: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.actions, Unset): + actions = [] + for actions_item_data in self.actions: + actions_item = actions_item_data.to_dict() + actions.append(actions_item) + + message = self.message + + omni_chat_url = self.omni_chat_url + + result_summary = self.result_summary + + topic = self.topic + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if actions is not UNSET: + field_dict["actions"] = actions + if message is not UNSET: + field_dict["message"] = message + if omni_chat_url is not UNSET: + field_dict["omniChatUrl"] = omni_chat_url + if result_summary is not UNSET: + field_dict["resultSummary"] = result_summary + if topic is not UNSET: + field_dict["topic"] = topic + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_job_action import AiJobAction + + d = dict(src_dict) + _actions = d.pop("actions", UNSET) + actions: list[AiJobAction] | Unset = UNSET + if _actions is not UNSET: + actions = [] + for actions_item_data in _actions: + actions_item = AiJobAction.from_dict(actions_item_data) + + actions.append(actions_item) + + message = d.pop("message", UNSET) + + omni_chat_url = d.pop("omniChatUrl", UNSET) + + result_summary = d.pop("resultSummary", UNSET) + + topic = d.pop("topic", UNSET) + + ai_job_result_response = cls( + actions=actions, + message=message, + omni_chat_url=omni_chat_url, + result_summary=result_summary, + topic=topic, + ) + + ai_job_result_response.additional_properties = d + return ai_job_result_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_job_status_response.py b/omni_python_sdk/models/ai_job_status_response.py new file mode 100644 index 0000000..ea188c1 --- /dev/null +++ b/omni_python_sdk/models/ai_job_status_response.py @@ -0,0 +1,343 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.ai_job_status_response_state import AiJobStatusResponseState, check_ai_job_status_response_state +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.ai_job_status_response_error import AiJobStatusResponseError + from ..models.ai_job_status_response_progress_type_0 import AiJobStatusResponseProgressType0 + + +T = TypeVar("T", bound="AiJobStatusResponse") + + +@_attrs_define +class AiJobStatusResponse: + """ + Attributes: + branch_id (None | UUID): Branch ID used for model context, or null if querying the main shared model. + conversation_id (UUID): The conversation this job belongs to. Use this to submit follow-up jobs in the same + conversation thread. Example: 660e8400-e29b-41d4-a716-446655440001. + created_at (datetime.datetime): When the job was submitted. Example: 2025-01-15T10:00:00.000Z. + id (UUID): The unique identifier for this job. Example: 550e8400-e29b-41d4-a716-446655440000. + model_id (None | UUID): The shared model ID used for query generation. Example: + 770e8400-e29b-41d4-a716-446655440002. + omni_chat_url (str): URL to view this conversation in the Omni chat interface. Opens the chat session where the + job actions and results are visible. Example: https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001. + organization_id (UUID): The organization that owns this job. Example: 880e8400-e29b-41d4-a716-446655440003. + prompt (str): The natural language prompt that was submitted. Example: What are the top 5 products by revenue?. + state (AiJobStatusResponseState): Current state of the job. Terminal states are COMPLETE, FAILED, and CANCELLED. + Poll until the job reaches a terminal state. Example: QUEUED. + topic_name (None | str): Topic name used to scope query generation, or null if the AI selected the topic + automatically. Example: order_items. + updated_at (datetime.datetime): When the job record was last modified. Example: 2025-01-15T10:00:05.000Z. + user_id (UUID): The user ID who created (or is associated with) this job. Example: + 990e8400-e29b-41d4-a716-446655440004. + cancelled_at (datetime.datetime | Unset): When the job was cancelled. Only present in CANCELLED state. Example: + 2025-01-15T10:00:12.000Z. + cancelled_by (UUID | Unset): User ID of who cancelled the job. Only present in CANCELLED state. Example: + 990e8400-e29b-41d4-a716-446655440004. + completed_at (datetime.datetime | Unset): When the job finished (successfully or with error). Present in + COMPLETE and FAILED states. Example: 2025-01-15T10:01:30.000Z. + error (AiJobStatusResponseError | Unset): Error details explaining why the job failed. Only present in FAILED + state. + execution_started_at (datetime.datetime | Unset): When execution began. Present once the job transitions from + QUEUED to EXECUTING. May be absent on jobs that failed or were cancelled before execution started. Example: + 2025-01-15T10:00:05.000Z. + progress (AiJobStatusResponseProgressType0 | None | Unset): Real-time progress information. Only present in + EXECUTING state. Null if no progress has been reported yet. Updated in real-time as the AI works through + iterations. + result_summary (str | Unset): Markdown-formatted summary of the job result. Only present in COMPLETE state. For + the full result with query details and data, use GET /api/v1/ai/jobs/{jobId}/result. Example: ### Top 5 Products + by Revenue + + 1. **Sunglasses** - $678,994 + 2. **Jeans** - $475,072. + """ + + branch_id: None | UUID + conversation_id: UUID + created_at: datetime.datetime + id: UUID + model_id: None | UUID + omni_chat_url: str + organization_id: UUID + prompt: str + state: AiJobStatusResponseState + topic_name: None | str + updated_at: datetime.datetime + user_id: UUID + cancelled_at: datetime.datetime | Unset = UNSET + cancelled_by: UUID | Unset = UNSET + completed_at: datetime.datetime | Unset = UNSET + error: AiJobStatusResponseError | Unset = UNSET + execution_started_at: datetime.datetime | Unset = UNSET + progress: AiJobStatusResponseProgressType0 | None | Unset = UNSET + result_summary: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.ai_job_status_response_progress_type_0 import AiJobStatusResponseProgressType0 + + branch_id: None | str + if isinstance(self.branch_id, UUID): + branch_id = str(self.branch_id) + else: + branch_id = self.branch_id + + conversation_id = str(self.conversation_id) + + created_at = self.created_at.isoformat() + + id = str(self.id) + + model_id: None | str + if isinstance(self.model_id, UUID): + model_id = str(self.model_id) + else: + model_id = self.model_id + + omni_chat_url = self.omni_chat_url + + organization_id = str(self.organization_id) + + prompt = self.prompt + + state: str = self.state + + topic_name: None | str + topic_name = self.topic_name + + updated_at = self.updated_at.isoformat() + + user_id = str(self.user_id) + + cancelled_at: str | Unset = UNSET + if not isinstance(self.cancelled_at, Unset): + cancelled_at = self.cancelled_at.isoformat() + + cancelled_by: str | Unset = UNSET + if not isinstance(self.cancelled_by, Unset): + cancelled_by = str(self.cancelled_by) + + completed_at: str | Unset = UNSET + if not isinstance(self.completed_at, Unset): + completed_at = self.completed_at.isoformat() + + error: dict[str, Any] | Unset = UNSET + if not isinstance(self.error, Unset): + error = self.error.to_dict() + + execution_started_at: str | Unset = UNSET + if not isinstance(self.execution_started_at, Unset): + execution_started_at = self.execution_started_at.isoformat() + + progress: dict[str, Any] | None | Unset + if isinstance(self.progress, Unset): + progress = UNSET + elif isinstance(self.progress, AiJobStatusResponseProgressType0): + progress = self.progress.to_dict() + else: + progress = self.progress + + result_summary = self.result_summary + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "branchId": branch_id, + "conversationId": conversation_id, + "createdAt": created_at, + "id": id, + "modelId": model_id, + "omniChatUrl": omni_chat_url, + "organizationId": organization_id, + "prompt": prompt, + "state": state, + "topicName": topic_name, + "updatedAt": updated_at, + "userId": user_id, + } + ) + if cancelled_at is not UNSET: + field_dict["cancelledAt"] = cancelled_at + if cancelled_by is not UNSET: + field_dict["cancelledBy"] = cancelled_by + if completed_at is not UNSET: + field_dict["completedAt"] = completed_at + if error is not UNSET: + field_dict["error"] = error + if execution_started_at is not UNSET: + field_dict["executionStartedAt"] = execution_started_at + if progress is not UNSET: + field_dict["progress"] = progress + if result_summary is not UNSET: + field_dict["resultSummary"] = result_summary + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_job_status_response_error import AiJobStatusResponseError + from ..models.ai_job_status_response_progress_type_0 import AiJobStatusResponseProgressType0 + + d = dict(src_dict) + + def _parse_branch_id(data: object) -> None | UUID: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + branch_id_type_0 = UUID(data) + + return branch_id_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UUID, data) + + branch_id = _parse_branch_id(d.pop("branchId")) + + conversation_id = UUID(d.pop("conversationId")) + + created_at = datetime.datetime.fromisoformat(d.pop("createdAt")) + + id = UUID(d.pop("id")) + + def _parse_model_id(data: object) -> None | UUID: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + model_id_type_0 = UUID(data) + + return model_id_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UUID, data) + + model_id = _parse_model_id(d.pop("modelId")) + + omni_chat_url = d.pop("omniChatUrl") + + organization_id = UUID(d.pop("organizationId")) + + prompt = d.pop("prompt") + + state = check_ai_job_status_response_state(d.pop("state")) + + def _parse_topic_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + topic_name = _parse_topic_name(d.pop("topicName")) + + updated_at = datetime.datetime.fromisoformat(d.pop("updatedAt")) + + user_id = UUID(d.pop("userId")) + + _cancelled_at = d.pop("cancelledAt", UNSET) + cancelled_at: datetime.datetime | Unset + if isinstance(_cancelled_at, Unset): + cancelled_at = UNSET + else: + cancelled_at = datetime.datetime.fromisoformat(_cancelled_at) + + _cancelled_by = d.pop("cancelledBy", UNSET) + cancelled_by: UUID | Unset + if isinstance(_cancelled_by, Unset): + cancelled_by = UNSET + else: + cancelled_by = UUID(_cancelled_by) + + _completed_at = d.pop("completedAt", UNSET) + completed_at: datetime.datetime | Unset + if isinstance(_completed_at, Unset): + completed_at = UNSET + else: + completed_at = datetime.datetime.fromisoformat(_completed_at) + + _error = d.pop("error", UNSET) + error: AiJobStatusResponseError | Unset + if isinstance(_error, Unset): + error = UNSET + else: + error = AiJobStatusResponseError.from_dict(_error) + + _execution_started_at = d.pop("executionStartedAt", UNSET) + execution_started_at: datetime.datetime | Unset + if isinstance(_execution_started_at, Unset): + execution_started_at = UNSET + else: + execution_started_at = datetime.datetime.fromisoformat(_execution_started_at) + + def _parse_progress(data: object) -> AiJobStatusResponseProgressType0 | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + progress_type_0 = AiJobStatusResponseProgressType0.from_dict(data) + + return progress_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(AiJobStatusResponseProgressType0 | None | Unset, data) + + progress = _parse_progress(d.pop("progress", UNSET)) + + result_summary = d.pop("resultSummary", UNSET) + + ai_job_status_response = cls( + branch_id=branch_id, + conversation_id=conversation_id, + created_at=created_at, + id=id, + model_id=model_id, + omni_chat_url=omni_chat_url, + organization_id=organization_id, + prompt=prompt, + state=state, + topic_name=topic_name, + updated_at=updated_at, + user_id=user_id, + cancelled_at=cancelled_at, + cancelled_by=cancelled_by, + completed_at=completed_at, + error=error, + execution_started_at=execution_started_at, + progress=progress, + result_summary=result_summary, + ) + + ai_job_status_response.additional_properties = d + return ai_job_status_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_job_status_response_error.py b/omni_python_sdk/models/ai_job_status_response_error.py new file mode 100644 index 0000000..1be6faf --- /dev/null +++ b/omni_python_sdk/models/ai_job_status_response_error.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="AiJobStatusResponseError") + + +@_attrs_define +class AiJobStatusResponseError: + """Error details explaining why the job failed. Only present in FAILED state. + + Attributes: + message (str): Human-readable error message. Example: Column 'revenue' not found in table 'orders'. + code (str | Unset): Machine-readable error code. Example: QUERY_EXECUTION_ERROR. + detail (str | Unset): Additional error detail or context. Example: The query timed out after 300 seconds. + """ + + message: str + code: str | Unset = UNSET + detail: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + code = self.code + + detail = self.detail + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + } + ) + if code is not UNSET: + field_dict["code"] = code + if detail is not UNSET: + field_dict["detail"] = detail + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + code = d.pop("code", UNSET) + + detail = d.pop("detail", UNSET) + + ai_job_status_response_error = cls( + message=message, + code=code, + detail=detail, + ) + + ai_job_status_response_error.additional_properties = d + return ai_job_status_response_error + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_job_status_response_progress_type_0.py b/omni_python_sdk/models/ai_job_status_response_progress_type_0.py new file mode 100644 index 0000000..d9f435d --- /dev/null +++ b/omni_python_sdk/models/ai_job_status_response_progress_type_0.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiJobStatusResponseProgressType0") + + +@_attrs_define +class AiJobStatusResponseProgressType0: + """Real-time progress information. Only present in EXECUTING state. Null if no progress has been reported yet. Updated + in real-time as the AI works through iterations. + + Attributes: + iteration (int): Current iteration number. The AI may take multiple iterations to refine queries and generate a + complete answer. Example: 2. + message (str): Human-readable status message describing what the AI is currently doing. Example: Running query: + Top products by revenue. + updated_at (datetime.datetime): When this progress update was recorded. Example: 2025-01-15T10:00:08.000Z. + """ + + iteration: int + message: str + updated_at: datetime.datetime + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + iteration = self.iteration + + message = self.message + + updated_at = self.updated_at.isoformat() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "iteration": iteration, + "message": message, + "updatedAt": updated_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + iteration = d.pop("iteration") + + message = d.pop("message") + + updated_at = datetime.datetime.fromisoformat(d.pop("updatedAt")) + + ai_job_status_response_progress_type_0 = cls( + iteration=iteration, + message=message, + updated_at=updated_at, + ) + + ai_job_status_response_progress_type_0.additional_properties = d + return ai_job_status_response_progress_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_job_status_response_state.py b/omni_python_sdk/models/ai_job_status_response_state.py new file mode 100644 index 0000000..c9dfa96 --- /dev/null +++ b/omni_python_sdk/models/ai_job_status_response_state.py @@ -0,0 +1,18 @@ +from typing import Literal + +AiJobStatusResponseState = Literal["CANCELLED", "COMPLETE", "DELIVERING", "EXECUTING", "FAILED", "QUEUED"] + +AI_JOB_STATUS_RESPONSE_STATE_VALUES: set[AiJobStatusResponseState] = { + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED", +} + + +def check_ai_job_status_response_state(value: str) -> AiJobStatusResponseState: + if value in AI_JOB_STATUS_RESPONSE_STATE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {AI_JOB_STATUS_RESPONSE_STATE_VALUES!r}") diff --git a/omni_python_sdk/models/ai_job_submit_body.py b/omni_python_sdk/models/ai_job_submit_body.py new file mode 100644 index 0000000..ab6795c --- /dev/null +++ b/omni_python_sdk/models/ai_job_submit_body.py @@ -0,0 +1,180 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.ai_job_submit_body_webhook_metadata import AiJobSubmitBodyWebhookMetadata + + +T = TypeVar("T", bound="AiJobSubmitBody") + + +@_attrs_define +class AiJobSubmitBody: + """ + Attributes: + model_id (UUID): The UUID of the model to query against. Must be a shared model, or a shared-extension model + usable as a workbook base. Example: 770e8400-e29b-41d4-a716-446655440002. + prompt (str): The natural language prompt for the AI to process. The AI will analyze your question, generate + appropriate queries, execute them, and return a summarized answer. Example: What are the top 5 products by + revenue this quarter?. + branch_id (UUID | Unset): Optional branch ID for the model. Must be a branch of the shared model specified by + modelId. Use this to query against in-progress model changes. Example: 550e8400-e29b-41d4-a716-446655440000. + conversation_id (UUID | Unset): Conversation ID to continue an existing conversation thread. The AI will have + access to the context from previous jobs in the same conversation. If omitted, a new conversation is created. + Only one active job can exist per conversation. Example: 660e8400-e29b-41d4-a716-446655440001. + progress_webhook_enabled (bool | Unset): When true, real-time progress events are POSTed to webhookUrl during + execution (e.g., "Searching for revenue fields", "Query returned 42 rows"). Requires webhookUrl. Progress events + are best-effort: single attempt, no retries, failures do not affect job execution. Default: False. Example: + True. + topic_name (str | Unset): Topic name to scope query generation. Topics define a set of related views and their + join paths. If not provided, the AI will automatically select the best topic. Use the pick-topic endpoint to + determine the right topic programmatically. Example: order_items. + webhook_metadata (AiJobSubmitBodyWebhookMetadata | Unset): Arbitrary metadata object that will be included + unchanged in webhook payloads. Use this to correlate webhook notifications with your own system (e.g., tracking + IDs, channel references). Example: {'externalId': 'task-123', 'slackChannel': 'C0123456789'}. + webhook_signing_secret (str | Unset): Secret key for HMAC-SHA256 webhook payload signing. When provided, each + webhook request includes X-Omni-Signature and X-Omni-Signature-Timestamp headers for verification. Required if + webhookUrl is specified. + webhook_url (str | Unset): URL to receive webhook POSTs. Always receives a terminal event (job.complete, + job.failed, or job.denied) when the job finishes; a job.denied event (e.g. the organization is over its AI + credit limit) additionally carries a reason field. When progressWebhookEnabled is true, also receives real-time + progress events during execution. Example: https://example.com/webhooks/omni. + """ + + model_id: UUID + prompt: str + branch_id: UUID | Unset = UNSET + conversation_id: UUID | Unset = UNSET + progress_webhook_enabled: bool | Unset = False + topic_name: str | Unset = UNSET + webhook_metadata: AiJobSubmitBodyWebhookMetadata | Unset = UNSET + webhook_signing_secret: str | Unset = UNSET + webhook_url: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + model_id = str(self.model_id) + + prompt = self.prompt + + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + conversation_id: str | Unset = UNSET + if not isinstance(self.conversation_id, Unset): + conversation_id = str(self.conversation_id) + + progress_webhook_enabled = self.progress_webhook_enabled + + topic_name = self.topic_name + + webhook_metadata: dict[str, Any] | Unset = UNSET + if not isinstance(self.webhook_metadata, Unset): + webhook_metadata = self.webhook_metadata.to_dict() + + webhook_signing_secret = self.webhook_signing_secret + + webhook_url = self.webhook_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "modelId": model_id, + "prompt": prompt, + } + ) + if branch_id is not UNSET: + field_dict["branchId"] = branch_id + if conversation_id is not UNSET: + field_dict["conversationId"] = conversation_id + if progress_webhook_enabled is not UNSET: + field_dict["progressWebhookEnabled"] = progress_webhook_enabled + if topic_name is not UNSET: + field_dict["topicName"] = topic_name + if webhook_metadata is not UNSET: + field_dict["webhookMetadata"] = webhook_metadata + if webhook_signing_secret is not UNSET: + field_dict["webhookSigningSecret"] = webhook_signing_secret + if webhook_url is not UNSET: + field_dict["webhookUrl"] = webhook_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_job_submit_body_webhook_metadata import AiJobSubmitBodyWebhookMetadata + + d = dict(src_dict) + model_id = UUID(d.pop("modelId")) + + prompt = d.pop("prompt") + + _branch_id = d.pop("branchId", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + _conversation_id = d.pop("conversationId", UNSET) + conversation_id: UUID | Unset + if isinstance(_conversation_id, Unset): + conversation_id = UNSET + else: + conversation_id = UUID(_conversation_id) + + progress_webhook_enabled = d.pop("progressWebhookEnabled", UNSET) + + topic_name = d.pop("topicName", UNSET) + + _webhook_metadata = d.pop("webhookMetadata", UNSET) + webhook_metadata: AiJobSubmitBodyWebhookMetadata | Unset + if isinstance(_webhook_metadata, Unset): + webhook_metadata = UNSET + else: + webhook_metadata = AiJobSubmitBodyWebhookMetadata.from_dict(_webhook_metadata) + + webhook_signing_secret = d.pop("webhookSigningSecret", UNSET) + + webhook_url = d.pop("webhookUrl", UNSET) + + ai_job_submit_body = cls( + model_id=model_id, + prompt=prompt, + branch_id=branch_id, + conversation_id=conversation_id, + progress_webhook_enabled=progress_webhook_enabled, + topic_name=topic_name, + webhook_metadata=webhook_metadata, + webhook_signing_secret=webhook_signing_secret, + webhook_url=webhook_url, + ) + + ai_job_submit_body.additional_properties = d + return ai_job_submit_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_job_submit_body_webhook_metadata.py b/omni_python_sdk/models/ai_job_submit_body_webhook_metadata.py new file mode 100644 index 0000000..c8d3d07 --- /dev/null +++ b/omni_python_sdk/models/ai_job_submit_body_webhook_metadata.py @@ -0,0 +1,53 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiJobSubmitBodyWebhookMetadata") + + +@_attrs_define +class AiJobSubmitBodyWebhookMetadata: + """Arbitrary metadata object that will be included unchanged in webhook payloads. Use this to correlate webhook + notifications with your own system (e.g., tracking IDs, channel references). + + Example: + {'externalId': 'task-123', 'slackChannel': 'C0123456789'} + + """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + ai_job_submit_body_webhook_metadata = cls() + + ai_job_submit_body_webhook_metadata.additional_properties = d + return ai_job_submit_body_webhook_metadata + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_job_submit_response.py b/omni_python_sdk/models/ai_job_submit_response.py new file mode 100644 index 0000000..437c3c9 --- /dev/null +++ b/omni_python_sdk/models/ai_job_submit_response.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiJobSubmitResponse") + + +@_attrs_define +class AiJobSubmitResponse: + """ + Attributes: + conversation_id (UUID): The conversation ID for this job. Pass this as conversationId in subsequent job + submissions to continue the conversation with additional context. Example: 660e8400-e29b-41d4-a716-446655440001. + job_id (UUID): The unique identifier for the created job. Use this to poll status via GET + /api/v1/ai/jobs/{jobId} or retrieve results via GET /api/v1/ai/jobs/{jobId}/result. Example: + 550e8400-e29b-41d4-a716-446655440000. + omni_chat_url (str): URL to view this conversation in the Omni chat interface. Opens the chat session where the + job actions and results are visible. Example: https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001. + """ + + conversation_id: UUID + job_id: UUID + omni_chat_url: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + conversation_id = str(self.conversation_id) + + job_id = str(self.job_id) + + omni_chat_url = self.omni_chat_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "conversationId": conversation_id, + "jobId": job_id, + "omniChatUrl": omni_chat_url, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + conversation_id = UUID(d.pop("conversationId")) + + job_id = UUID(d.pop("jobId")) + + omni_chat_url = d.pop("omniChatUrl") + + ai_job_submit_response = cls( + conversation_id=conversation_id, + job_id=job_id, + omni_chat_url=omni_chat_url, + ) + + ai_job_submit_response.additional_properties = d + return ai_job_submit_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_pick_topic_body.py b/omni_python_sdk/models/ai_pick_topic_body.py new file mode 100644 index 0000000..a7a867a --- /dev/null +++ b/omni_python_sdk/models/ai_pick_topic_body.py @@ -0,0 +1,132 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="AiPickTopicBody") + + +@_attrs_define +class AiPickTopicBody: + """ + Attributes: + model_id (UUID): The UUID of the shared model to query against. Only shared models are supported. Example: + 770e8400-e29b-41d4-a716-446655440002. + prompt (str): The natural language prompt to analyze. The AI will determine which topic best matches the data + described in this prompt. Example: How many orders were placed last month?. + branch_id (UUID | Unset): Optional branch ID for the model. Must be a branch of the shared model specified by + modelId. Example: 550e8400-e29b-41d4-a716-446655440000. + current_topic_name (str | Unset): The name of the current topic to scope query generation. If not provided, AI + will automatically select the best topic for your prompt. Example: order_items. + potential_topic_names (list[str] | Unset): Optional list of topic names to limit consideration to. If not + provided, all topics the user has access to in the model will be evaluated. Example: ['order_items', + 'customers', 'products']. + user_id (UUID | Unset): User ID to evaluate topic access as. Their permissions will be used for permission-aware + topic selection. Only valid with organization-scoped API keys. Personal access tokens always act as the + authenticated user. Example: 990e8400-e29b-41d4-a716-446655440004. + """ + + model_id: UUID + prompt: str + branch_id: UUID | Unset = UNSET + current_topic_name: str | Unset = UNSET + potential_topic_names: list[str] | Unset = UNSET + user_id: UUID | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + model_id = str(self.model_id) + + prompt = self.prompt + + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + current_topic_name = self.current_topic_name + + potential_topic_names: list[str] | Unset = UNSET + if not isinstance(self.potential_topic_names, Unset): + potential_topic_names = self.potential_topic_names + + user_id: str | Unset = UNSET + if not isinstance(self.user_id, Unset): + user_id = str(self.user_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "modelId": model_id, + "prompt": prompt, + } + ) + if branch_id is not UNSET: + field_dict["branchId"] = branch_id + if current_topic_name is not UNSET: + field_dict["currentTopicName"] = current_topic_name + if potential_topic_names is not UNSET: + field_dict["potentialTopicNames"] = potential_topic_names + if user_id is not UNSET: + field_dict["userId"] = user_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + model_id = UUID(d.pop("modelId")) + + prompt = d.pop("prompt") + + _branch_id = d.pop("branchId", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + current_topic_name = d.pop("currentTopicName", UNSET) + + potential_topic_names = cast(list[str], d.pop("potentialTopicNames", UNSET)) + + _user_id = d.pop("userId", UNSET) + user_id: UUID | Unset + if isinstance(_user_id, Unset): + user_id = UNSET + else: + user_id = UUID(_user_id) + + ai_pick_topic_body = cls( + model_id=model_id, + prompt=prompt, + branch_id=branch_id, + current_topic_name=current_topic_name, + potential_topic_names=potential_topic_names, + user_id=user_id, + ) + + ai_pick_topic_body.additional_properties = d + return ai_pick_topic_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_pick_topic_response.py b/omni_python_sdk/models/ai_pick_topic_response.py new file mode 100644 index 0000000..32d89f4 --- /dev/null +++ b/omni_python_sdk/models/ai_pick_topic_response.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiPickTopicResponse") + + +@_attrs_define +class AiPickTopicResponse: + """ + Attributes: + topic_id (str): The name of the topic that best matches the prompt. Use this as the topicName parameter when + calling generate-query or submitting an AI job. Example: order_items. + """ + + topic_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + topic_id = self.topic_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "topicId": topic_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + topic_id = d.pop("topicId") + + ai_pick_topic_response = cls( + topic_id=topic_id, + ) + + ai_pick_topic_response.additional_properties = d + return ai_pick_topic_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_query_sort.py b/omni_python_sdk/models/ai_query_sort.py new file mode 100644 index 0000000..8ea6c25 --- /dev/null +++ b/omni_python_sdk/models/ai_query_sort.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiQuerySort") + + +@_attrs_define +class AiQuerySort: + """ + Attributes: + column_name (str): Fully qualified field name to sort by (e.g., "view_name.field_name"). Example: + order_items.total_revenue. + sort_descending (bool): Whether to sort in descending order. Example: True. + """ + + column_name: str + sort_descending: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + column_name = self.column_name + + sort_descending = self.sort_descending + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "column_name": column_name, + "sort_descending": sort_descending, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + column_name = d.pop("column_name") + + sort_descending = d.pop("sort_descending") + + ai_query_sort = cls( + column_name=column_name, + sort_descending=sort_descending, + ) + + ai_query_sort.additional_properties = d + return ai_query_sort + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_search_omni_docs_body.py b/omni_python_sdk/models/ai_search_omni_docs_body.py new file mode 100644 index 0000000..c96c225 --- /dev/null +++ b/omni_python_sdk/models/ai_search_omni_docs_body.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiSearchOmniDocsBody") + + +@_attrs_define +class AiSearchOmniDocsBody: + """ + Attributes: + question (str): A natural language question about Omni features, configuration, modeling, dashboards, or other + topics covered in the Omni documentation. Example: How do I create a dashboard filter?. + """ + + question: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + question = self.question + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "question": question, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + question = d.pop("question") + + ai_search_omni_docs_body = cls( + question=question, + ) + + ai_search_omni_docs_body.additional_properties = d + return ai_search_omni_docs_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_search_omni_docs_response.py b/omni_python_sdk/models/ai_search_omni_docs_response.py new file mode 100644 index 0000000..eac6d9f --- /dev/null +++ b/omni_python_sdk/models/ai_search_omni_docs_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.ai_search_omni_docs_response_sources_item import AiSearchOmniDocsResponseSourcesItem + + +T = TypeVar("T", bound="AiSearchOmniDocsResponse") + + +@_attrs_define +class AiSearchOmniDocsResponse: + """ + Attributes: + answer (str): A synthesized answer to the question, based on the Omni documentation. Example: To create a + dashboard filter, navigate to your dashboard and click the "Add Filter" button.... + sources (list[AiSearchOmniDocsResponseSourcesItem]): List of documentation pages that were used to synthesize + the answer. + """ + + answer: str + sources: list[AiSearchOmniDocsResponseSourcesItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + answer = self.answer + + sources = [] + for sources_item_data in self.sources: + sources_item = sources_item_data.to_dict() + sources.append(sources_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "answer": answer, + "sources": sources, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_search_omni_docs_response_sources_item import AiSearchOmniDocsResponseSourcesItem + + d = dict(src_dict) + answer = d.pop("answer") + + sources = [] + _sources = d.pop("sources") + for sources_item_data in _sources: + sources_item = AiSearchOmniDocsResponseSourcesItem.from_dict(sources_item_data) + + sources.append(sources_item) + + ai_search_omni_docs_response = cls( + answer=answer, + sources=sources, + ) + + ai_search_omni_docs_response.additional_properties = d + return ai_search_omni_docs_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_search_omni_docs_response_sources_item.py b/omni_python_sdk/models/ai_search_omni_docs_response_sources_item.py new file mode 100644 index 0000000..0fdbee1 --- /dev/null +++ b/omni_python_sdk/models/ai_search_omni_docs_response_sources_item.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiSearchOmniDocsResponseSourcesItem") + + +@_attrs_define +class AiSearchOmniDocsResponseSourcesItem: + """ + Attributes: + title (str): The title of the source documentation page. Example: Dashboard Filters. + url (str): URL of the source documentation page. Example: https://docs.omni.co/docs/dashboards/filters. + """ + + title: str + url: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + title = self.title + + url = self.url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "title": title, + "url": url, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + title = d.pop("title") + + url = d.pop("url") + + ai_search_omni_docs_response_sources_item = cls( + title=title, + url=url, + ) + + ai_search_omni_docs_response_sources_item.additional_properties = d + return ai_search_omni_docs_response_sources_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_semantic_query.py b/omni_python_sdk/models/ai_semantic_query.py new file mode 100644 index 0000000..f2f804a --- /dev/null +++ b/omni_python_sdk/models/ai_semantic_query.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiSemanticQuery") + + +@_attrs_define +class AiSemanticQuery: + """The generated semantic query definition. Null if generation failed. This query can be passed directly to the POST + /api/v1/query/run endpoint. (Not statically modeled; use plain dicts.) + + """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + ai_semantic_query = cls() + + ai_semantic_query.additional_properties = d + return ai_semantic_query + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_topic_params.py b/omni_python_sdk/models/ai_topic_params.py new file mode 100644 index 0000000..fd87d6a --- /dev/null +++ b/omni_python_sdk/models/ai_topic_params.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="AiTopicParams") + + +@_attrs_define +class AiTopicParams: + """ + Attributes: + model_id (UUID): The UUID of the shared model to query against. Only shared models are supported. Example: + 770e8400-e29b-41d4-a716-446655440002. + branch_id (UUID | Unset): Optional branch ID for the model. Must be a branch of the shared model specified by + modelId. Example: 550e8400-e29b-41d4-a716-446655440000. + current_topic_name (str | Unset): The name of the current topic to scope query generation. If not provided, AI + will automatically select the best topic for your prompt. Example: order_items. + """ + + model_id: UUID + branch_id: UUID | Unset = UNSET + current_topic_name: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + model_id = str(self.model_id) + + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + current_topic_name = self.current_topic_name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "modelId": model_id, + } + ) + if branch_id is not UNSET: + field_dict["branchId"] = branch_id + if current_topic_name is not UNSET: + field_dict["currentTopicName"] = current_topic_name + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + model_id = UUID(d.pop("modelId")) + + _branch_id = d.pop("branchId", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + current_topic_name = d.pop("currentTopicName", UNSET) + + ai_topic_params = cls( + model_id=model_id, + branch_id=branch_id, + current_topic_name=current_topic_name, + ) + + ai_topic_params.additional_properties = d + return ai_topic_params + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_user_credit_limit_entry.py b/omni_python_sdk/models/ai_user_credit_limit_entry.py new file mode 100644 index 0000000..2ea59b1 --- /dev/null +++ b/omni_python_sdk/models/ai_user_credit_limit_entry.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="AiUserCreditLimitEntry") + + +@_attrs_define +class AiUserCreditLimitEntry: + """ + Attributes: + user_id (str): The user's id within this organization. Example: f4a2b3c8-0d1e-4f5a-9b6c-7d8e9f0a1b2c. + credit_limit (float | None | Unset): The user's individual AI credit limit for the billing period, or `null` for + unlimited. Either way this overrides the org default. Mutually exclusive with `useDefaultLimit`. Example: 50. + use_default_limit (bool | Unset): Removes the user's individual limit so they follow the org default. Mutually + exclusive with `creditLimit`. + """ + + user_id: str + credit_limit: float | None | Unset = UNSET + use_default_limit: bool | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + user_id = self.user_id + + credit_limit: float | None | Unset + if isinstance(self.credit_limit, Unset): + credit_limit = UNSET + else: + credit_limit = self.credit_limit + + use_default_limit = self.use_default_limit + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "userId": user_id, + } + ) + if credit_limit is not UNSET: + field_dict["creditLimit"] = credit_limit + if use_default_limit is not UNSET: + field_dict["useDefaultLimit"] = use_default_limit + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + user_id = d.pop("userId") + + def _parse_credit_limit(data: object) -> float | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(float | None | Unset, data) + + credit_limit = _parse_credit_limit(d.pop("creditLimit", UNSET)) + + use_default_limit = d.pop("useDefaultLimit", UNSET) + + ai_user_credit_limit_entry = cls( + user_id=user_id, + credit_limit=credit_limit, + use_default_limit=use_default_limit, + ) + + return ai_user_credit_limit_entry diff --git a/omni_python_sdk/models/ai_user_credit_limits_response.py b/omni_python_sdk/models/ai_user_credit_limits_response.py new file mode 100644 index 0000000..149fec8 --- /dev/null +++ b/omni_python_sdk/models/ai_user_credit_limits_response.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.ai_user_credit_limits_response_users_item import AiUserCreditLimitsResponseUsersItem + + +T = TypeVar("T", bound="AiUserCreditLimitsResponse") + + +@_attrs_define +class AiUserCreditLimitsResponse: + """ + Attributes: + users (list[AiUserCreditLimitsResponseUsersItem]): + """ + + users: list[AiUserCreditLimitsResponseUsersItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + users = [] + for users_item_data in self.users: + users_item = users_item_data.to_dict() + users.append(users_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "users": users, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_user_credit_limits_response_users_item import AiUserCreditLimitsResponseUsersItem + + d = dict(src_dict) + users = [] + _users = d.pop("users") + for users_item_data in _users: + users_item = AiUserCreditLimitsResponseUsersItem.from_dict(users_item_data) + + users.append(users_item) + + ai_user_credit_limits_response = cls( + users=users, + ) + + ai_user_credit_limits_response.additional_properties = d + return ai_user_credit_limits_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_user_credit_limits_response_users_item.py b/omni_python_sdk/models/ai_user_credit_limits_response_users_item.py new file mode 100644 index 0000000..59b37a7 --- /dev/null +++ b/omni_python_sdk/models/ai_user_credit_limits_response_users_item.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiUserCreditLimitsResponseUsersItem") + + +@_attrs_define +class AiUserCreditLimitsResponseUsersItem: + """ + Attributes: + credit_limit (float | None): The user's effective AI credit limit, or `null` for unlimited. Example: 50. + user_id (str): The user's id within this organization. Example: f4a2b3c8-0d1e-4f5a-9b6c-7d8e9f0a1b2c. + uses_default_limit (bool): True when the user has no individual limit and follows the org default. + """ + + credit_limit: float | None + user_id: str + uses_default_limit: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + credit_limit: float | None + credit_limit = self.credit_limit + + user_id = self.user_id + + uses_default_limit = self.uses_default_limit + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "creditLimit": credit_limit, + "userId": user_id, + "usesDefaultLimit": uses_default_limit, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_credit_limit(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + credit_limit = _parse_credit_limit(d.pop("creditLimit")) + + user_id = d.pop("userId") + + uses_default_limit = d.pop("usesDefaultLimit") + + ai_user_credit_limits_response_users_item = cls( + credit_limit=credit_limit, + user_id=user_id, + uses_default_limit=uses_default_limit, + ) + + ai_user_credit_limits_response_users_item.additional_properties = d + return ai_user_credit_limits_response_users_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_user_credit_limits_update_body.py b/omni_python_sdk/models/ai_user_credit_limits_update_body.py new file mode 100644 index 0000000..a8d16e0 --- /dev/null +++ b/omni_python_sdk/models/ai_user_credit_limits_update_body.py @@ -0,0 +1,57 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define + +if TYPE_CHECKING: + from ..models.ai_user_credit_limit_entry import AiUserCreditLimitEntry + + +T = TypeVar("T", bound="AiUserCreditLimitsUpdateBody") + + +@_attrs_define +class AiUserCreditLimitsUpdateBody: + """ + Attributes: + users (list[AiUserCreditLimitEntry]): Users to update, at most 1000 per request. Each entry has a `userId` plus + exactly one of `creditLimit` (number or `null`) or `useDefaultLimit: true`. + """ + + users: list[AiUserCreditLimitEntry] + + def to_dict(self) -> dict[str, Any]: + users = [] + for users_item_data in self.users: + users_item = users_item_data.to_dict() + users.append(users_item) + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "users": users, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_user_credit_limit_entry import AiUserCreditLimitEntry + + d = dict(src_dict) + users = [] + _users = d.pop("users") + for users_item_data in _users: + users_item = AiUserCreditLimitEntry.from_dict(users_item_data) + + users.append(users_item) + + ai_user_credit_limits_update_body = cls( + users=users, + ) + + return ai_user_credit_limits_update_body diff --git a/omni_python_sdk/models/api_document.py b/omni_python_sdk/models/api_document.py new file mode 100644 index 0000000..c827339 --- /dev/null +++ b/omni_python_sdk/models/api_document.py @@ -0,0 +1,289 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.content_share_scope import ContentShareScope, check_content_share_scope +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.api_document_count import ApiDocumentCount + from ..models.internal_folder_type_0 import InternalFolderType0 + from ..models.owner_internal import OwnerInternal + + +T = TypeVar("T", bound="ApiDocument") + + +@_attrs_define +class ApiDocument: + """ + Attributes: + name (str): Content name + owner (OwnerInternal): Content owner + scope (ContentShareScope): Content access scope + connection_id (str): Connection ID + deleted (bool): Whether document is deleted + folder (InternalFolderType0 | None): Parent folder + has_app (bool): Whether document has an app + has_dashboard (bool): Whether document has a dashboard + identifier (str): Document identifier + updated_at (datetime.datetime | None): Last updated timestamp + url (str): URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an + app, otherwise the workbook URL. Example: https://org.omni.co/dashboards/abc123. + field_count (ApiDocumentCount | Unset): Document counts + description (None | str | Unset): Document description + labels (list[str] | Unset): Applied labels + last_viewed_at (datetime.datetime | None | Unset): Last time the dashboard was viewed + visits (float | None | Unset): Number of dashboard visits + """ + + name: str + owner: OwnerInternal + scope: ContentShareScope + connection_id: str + deleted: bool + folder: InternalFolderType0 | None + has_app: bool + has_dashboard: bool + identifier: str + updated_at: datetime.datetime | None + url: str + field_count: ApiDocumentCount | Unset = UNSET + description: None | str | Unset = UNSET + labels: list[str] | Unset = UNSET + last_viewed_at: datetime.datetime | None | Unset = UNSET + visits: float | None | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.internal_folder_type_0 import InternalFolderType0 + + name = self.name + + owner = self.owner.to_dict() + + scope: str = self.scope + + connection_id = self.connection_id + + deleted = self.deleted + + folder: dict[str, Any] | None + if isinstance(self.folder, InternalFolderType0): + folder = self.folder.to_dict() + else: + folder = self.folder + + has_app = self.has_app + + has_dashboard = self.has_dashboard + + identifier = self.identifier + + updated_at: None | str + if isinstance(self.updated_at, datetime.datetime): + updated_at = self.updated_at.isoformat() + else: + updated_at = self.updated_at + + url = self.url + + field_count: dict[str, Any] | Unset = UNSET + if not isinstance(self.field_count, Unset): + field_count = self.field_count.to_dict() + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + labels: list[str] | Unset = UNSET + if not isinstance(self.labels, Unset): + labels = self.labels + + last_viewed_at: None | str | Unset + if isinstance(self.last_viewed_at, Unset): + last_viewed_at = UNSET + elif isinstance(self.last_viewed_at, datetime.datetime): + last_viewed_at = self.last_viewed_at.isoformat() + else: + last_viewed_at = self.last_viewed_at + + visits: float | None | Unset + if isinstance(self.visits, Unset): + visits = UNSET + else: + visits = self.visits + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "owner": owner, + "scope": scope, + "connectionId": connection_id, + "deleted": deleted, + "folder": folder, + "hasApp": has_app, + "hasDashboard": has_dashboard, + "identifier": identifier, + "updatedAt": updated_at, + "url": url, + } + ) + if field_count is not UNSET: + field_dict["_count"] = field_count + if description is not UNSET: + field_dict["description"] = description + if labels is not UNSET: + field_dict["labels"] = labels + if last_viewed_at is not UNSET: + field_dict["lastViewedAt"] = last_viewed_at + if visits is not UNSET: + field_dict["visits"] = visits + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.api_document_count import ApiDocumentCount + from ..models.internal_folder_type_0 import InternalFolderType0 + from ..models.owner_internal import OwnerInternal + + d = dict(src_dict) + name = d.pop("name") + + owner = OwnerInternal.from_dict(d.pop("owner")) + + scope = check_content_share_scope(d.pop("scope")) + + connection_id = d.pop("connectionId") + + deleted = d.pop("deleted") + + def _parse_folder(data: object) -> InternalFolderType0 | None: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_internal_folder_type_0 = InternalFolderType0.from_dict(data) + + return componentsschemas_internal_folder_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(InternalFolderType0 | None, data) + + folder = _parse_folder(d.pop("folder")) + + has_app = d.pop("hasApp") + + has_dashboard = d.pop("hasDashboard") + + identifier = d.pop("identifier") + + def _parse_updated_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + updated_at_type_0 = datetime.datetime.fromisoformat(data) + + return updated_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + updated_at = _parse_updated_at(d.pop("updatedAt")) + + url = d.pop("url") + + _field_count = d.pop("_count", UNSET) + field_count: ApiDocumentCount | Unset + if isinstance(_field_count, Unset): + field_count = UNSET + else: + field_count = ApiDocumentCount.from_dict(_field_count) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + labels = cast(list[str], d.pop("labels", UNSET)) + + def _parse_last_viewed_at(data: object) -> datetime.datetime | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + last_viewed_at_type_0 = datetime.datetime.fromisoformat(data) + + return last_viewed_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None | Unset, data) + + last_viewed_at = _parse_last_viewed_at(d.pop("lastViewedAt", UNSET)) + + def _parse_visits(data: object) -> float | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(float | None | Unset, data) + + visits = _parse_visits(d.pop("visits", UNSET)) + + api_document = cls( + name=name, + owner=owner, + scope=scope, + connection_id=connection_id, + deleted=deleted, + folder=folder, + has_app=has_app, + has_dashboard=has_dashboard, + identifier=identifier, + updated_at=updated_at, + url=url, + field_count=field_count, + description=description, + labels=labels, + last_viewed_at=last_viewed_at, + visits=visits, + ) + + api_document.additional_properties = d + return api_document + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_document_count.py b/omni_python_sdk/models/api_document_count.py new file mode 100644 index 0000000..8145232 --- /dev/null +++ b/omni_python_sdk/models/api_document_count.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiDocumentCount") + + +@_attrs_define +class ApiDocumentCount: + """Document counts + + Attributes: + favorites (float): Number of users who favorited + views (float): Number of views + """ + + favorites: float + views: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + favorites = self.favorites + + views = self.views + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "favorites": favorites, + "views": views, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + favorites = d.pop("favorites") + + views = d.pop("views") + + api_document_count = cls( + favorites=favorites, + views=views, + ) + + api_document_count.additional_properties = d + return api_document_count + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_draft.py b/omni_python_sdk/models/api_draft.py new file mode 100644 index 0000000..226292a --- /dev/null +++ b/omni_python_sdk/models/api_draft.py @@ -0,0 +1,167 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.api_draft_status import ApiDraftStatus, check_api_draft_status + +if TYPE_CHECKING: + from ..models.api_draft_actor import ApiDraftActor + from ..models.api_draft_branch_type_0 import ApiDraftBranchType0 + + +T = TypeVar("T", bound="ApiDraft") + + +@_attrs_define +class ApiDraft: + """ + Attributes: + branch (ApiDraftBranchType0 | None): Branch the draft is attached to, or null for a draft on main + created_at (datetime.datetime): When the draft was created + created_by (ApiDraftActor): User who created the draft + draft_out_of_date (bool): True when the published document was published more recently than the draft was + created (the draft is based on a stale baseline) + identifier (str): Draft workbook identifier — use this to address the draft + last_edited_by (ApiDraftActor): User who created the draft + published_identifier (str): Identifier of the published document the draft is for + status (ApiDraftStatus): Lifecycle status: "active" for current drafts, "archived" for soft-deleted drafts + (retained ~7 days) + updated_at (datetime.datetime): Most recent edit time on the draft workbook + workbook_model_id (UUID): omni_model ID for the draft workbook + """ + + branch: ApiDraftBranchType0 | None + created_at: datetime.datetime + created_by: ApiDraftActor + draft_out_of_date: bool + identifier: str + last_edited_by: ApiDraftActor + published_identifier: str + status: ApiDraftStatus + updated_at: datetime.datetime + workbook_model_id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.api_draft_branch_type_0 import ApiDraftBranchType0 + + branch: dict[str, Any] | None + if isinstance(self.branch, ApiDraftBranchType0): + branch = self.branch.to_dict() + else: + branch = self.branch + + created_at = self.created_at.isoformat() + + created_by = self.created_by.to_dict() + + draft_out_of_date = self.draft_out_of_date + + identifier = self.identifier + + last_edited_by = self.last_edited_by.to_dict() + + published_identifier = self.published_identifier + + status: str = self.status + + updated_at = self.updated_at.isoformat() + + workbook_model_id = str(self.workbook_model_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "branch": branch, + "createdAt": created_at, + "createdBy": created_by, + "draftOutOfDate": draft_out_of_date, + "identifier": identifier, + "lastEditedBy": last_edited_by, + "publishedIdentifier": published_identifier, + "status": status, + "updatedAt": updated_at, + "workbookModelId": workbook_model_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.api_draft_actor import ApiDraftActor + from ..models.api_draft_branch_type_0 import ApiDraftBranchType0 + + d = dict(src_dict) + + def _parse_branch(data: object) -> ApiDraftBranchType0 | None: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_api_draft_branch_type_0 = ApiDraftBranchType0.from_dict(data) + + return componentsschemas_api_draft_branch_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(ApiDraftBranchType0 | None, data) + + branch = _parse_branch(d.pop("branch")) + + created_at = datetime.datetime.fromisoformat(d.pop("createdAt")) + + created_by = ApiDraftActor.from_dict(d.pop("createdBy")) + + draft_out_of_date = d.pop("draftOutOfDate") + + identifier = d.pop("identifier") + + last_edited_by = ApiDraftActor.from_dict(d.pop("lastEditedBy")) + + published_identifier = d.pop("publishedIdentifier") + + status = check_api_draft_status(d.pop("status")) + + updated_at = datetime.datetime.fromisoformat(d.pop("updatedAt")) + + workbook_model_id = UUID(d.pop("workbookModelId")) + + api_draft = cls( + branch=branch, + created_at=created_at, + created_by=created_by, + draft_out_of_date=draft_out_of_date, + identifier=identifier, + last_edited_by=last_edited_by, + published_identifier=published_identifier, + status=status, + updated_at=updated_at, + workbook_model_id=workbook_model_id, + ) + + api_draft.additional_properties = d + return api_draft + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_draft_actor.py b/omni_python_sdk/models/api_draft_actor.py new file mode 100644 index 0000000..1f4c812 --- /dev/null +++ b/omni_python_sdk/models/api_draft_actor.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiDraftActor") + + +@_attrs_define +class ApiDraftActor: + """User who created the draft + + Attributes: + name (str): Display name + """ + + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + name = d.pop("name") + + api_draft_actor = cls( + name=name, + ) + + api_draft_actor.additional_properties = d + return api_draft_actor + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_draft_branch_type_0.py b/omni_python_sdk/models/api_draft_branch_type_0.py new file mode 100644 index 0000000..f8db17c --- /dev/null +++ b/omni_python_sdk/models/api_draft_branch_type_0.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiDraftBranchType0") + + +@_attrs_define +class ApiDraftBranchType0: + """Branch the draft is attached to, or null for a draft on main + + Attributes: + id (UUID): Branch (omni model) ID + name (str): Branch name + """ + + id: UUID + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = UUID(d.pop("id")) + + name = d.pop("name") + + api_draft_branch_type_0 = cls( + id=id, + name=name, + ) + + api_draft_branch_type_0.additional_properties = d + return api_draft_branch_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_draft_status.py b/omni_python_sdk/models/api_draft_status.py new file mode 100644 index 0000000..95fc1e9 --- /dev/null +++ b/omni_python_sdk/models/api_draft_status.py @@ -0,0 +1,14 @@ +from typing import Literal + +ApiDraftStatus = Literal["active", "archived"] + +API_DRAFT_STATUS_VALUES: set[ApiDraftStatus] = { + "active", + "archived", +} + + +def check_api_draft_status(value: str) -> ApiDraftStatus: + if value in API_DRAFT_STATUS_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {API_DRAFT_STATUS_VALUES!r}") diff --git a/omni_python_sdk/models/api_error_400.py b/omni_python_sdk/models/api_error_400.py new file mode 100644 index 0000000..69e5126 --- /dev/null +++ b/omni_python_sdk/models/api_error_400.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiError400") + + +@_attrs_define +class ApiError400: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: Bad Request: prompt: Required. + status (int): HTTP status code of the error. Example: 400. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + api_error_400 = cls( + detail=detail, + status=status, + ) + + api_error_400.additional_properties = d + return api_error_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_error_401.py b/omni_python_sdk/models/api_error_401.py new file mode 100644 index 0000000..9f16676 --- /dev/null +++ b/omni_python_sdk/models/api_error_401.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiError401") + + +@_attrs_define +class ApiError401: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: Unauthorized: Missing or invalid + API key. + status (int): HTTP status code of the error. Example: 401. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + api_error_401 = cls( + detail=detail, + status=status, + ) + + api_error_401.additional_properties = d + return api_error_401 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_error_403.py b/omni_python_sdk/models/api_error_403.py new file mode 100644 index 0000000..eb82819 --- /dev/null +++ b/omni_python_sdk/models/api_error_403.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiError403") + + +@_attrs_define +class ApiError403: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: Forbidden: AI query generation + is not enabled for this organization. + status (int): HTTP status code of the error. Example: 403. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + api_error_403 = cls( + detail=detail, + status=status, + ) + + api_error_403.additional_properties = d + return api_error_403 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_error_404.py b/omni_python_sdk/models/api_error_404.py new file mode 100644 index 0000000..414332d --- /dev/null +++ b/omni_python_sdk/models/api_error_404.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiError404") + + +@_attrs_define +class ApiError404: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: Model + 770e8400-e29b-41d4-a716-446655440002 not found. + status (int): HTTP status code of the error. Example: 404. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + api_error_404 = cls( + detail=detail, + status=status, + ) + + api_error_404.additional_properties = d + return api_error_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_error_409.py b/omni_python_sdk/models/api_error_409.py new file mode 100644 index 0000000..1598216 --- /dev/null +++ b/omni_python_sdk/models/api_error_409.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiError409") + + +@_attrs_define +class ApiError409: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: An active job already exists for + this conversation. + status (int): HTTP status code of the error. Example: 409. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + api_error_409 = cls( + detail=detail, + status=status, + ) + + api_error_409.additional_properties = d + return api_error_409 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_error_422.py b/omni_python_sdk/models/api_error_422.py new file mode 100644 index 0000000..af3c16c --- /dev/null +++ b/omni_python_sdk/models/api_error_422.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiError422") + + +@_attrs_define +class ApiError422: + """ + Attributes: + error (str): Human-readable error message describing what went wrong. Example: No Arrow IPC data available for + visualization. + """ + + error: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + error = self.error + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "error": error, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + error = d.pop("error") + + api_error_422 = cls( + error=error, + ) + + api_error_422.additional_properties = d + return api_error_422 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_error_429.py b/omni_python_sdk/models/api_error_429.py new file mode 100644 index 0000000..4344fc2 --- /dev/null +++ b/omni_python_sdk/models/api_error_429.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiError429") + + +@_attrs_define +class ApiError429: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: User has reached the maximum of + 100 routines. + status (int): HTTP status code of the error. Example: 429. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + api_error_429 = cls( + detail=detail, + status=status, + ) + + api_error_429.additional_properties = d + return api_error_429 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_key.py b/omni_python_sdk/models/api_key.py new file mode 100644 index 0000000..476a96e --- /dev/null +++ b/omni_python_sdk/models/api_key.py @@ -0,0 +1,126 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.api_key_type import ApiKeyType, check_api_key_type + +T = TypeVar("T", bound="ApiKey") + + +@_attrs_define +class ApiKey: + """ + Attributes: + created_at (datetime.datetime): ISO 8601 timestamp of when the token was created Example: + 2026-01-15T10:00:00.000Z. + enabled (bool): Whether the token can currently authenticate. A disabled token cannot authenticate but remains + visible until deleted. Example: True. + id (UUID): Unique identifier for the token Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890. + membership_id (None | UUID): Membership ID of the user the token is scoped to. Null for organization-level + tokens. Example: b2c3d4e5-f6a7-8901-bcde-f12345678901. + name (str): Human-readable name for the token Example: CI deployment key. + type_ (ApiKeyType): Token type: `organization` (org-level), `personal` (user-created personal access token), or + `mcp` (MCP OAuth grant). Example: organization. + """ + + created_at: datetime.datetime + enabled: bool + id: UUID + membership_id: None | UUID + name: str + type_: ApiKeyType + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created_at = self.created_at.isoformat() + + enabled = self.enabled + + id = str(self.id) + + membership_id: None | str + if isinstance(self.membership_id, UUID): + membership_id = str(self.membership_id) + else: + membership_id = self.membership_id + + name = self.name + + type_: str = self.type_ + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "createdAt": created_at, + "enabled": enabled, + "id": id, + "membershipId": membership_id, + "name": name, + "type": type_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + created_at = datetime.datetime.fromisoformat(d.pop("createdAt")) + + enabled = d.pop("enabled") + + id = UUID(d.pop("id")) + + def _parse_membership_id(data: object) -> None | UUID: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + membership_id_type_0 = UUID(data) + + return membership_id_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UUID, data) + + membership_id = _parse_membership_id(d.pop("membershipId")) + + name = d.pop("name") + + type_ = check_api_key_type(d.pop("type")) + + api_key = cls( + created_at=created_at, + enabled=enabled, + id=id, + membership_id=membership_id, + name=name, + type_=type_, + ) + + api_key.additional_properties = d + return api_key + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_key_delete_response.py b/omni_python_sdk/models/api_key_delete_response.py new file mode 100644 index 0000000..53c76a9 --- /dev/null +++ b/omni_python_sdk/models/api_key_delete_response.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiKeyDeleteResponse") + + +@_attrs_define +class ApiKeyDeleteResponse: + """ + Attributes: + message (str): Human-readable description of the outcome Example: API token revoked. + success (bool): Always `true` on a successful revocation + """ + + message: str + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + success = d.pop("success") + + api_key_delete_response = cls( + message=message, + success=success, + ) + + api_key_delete_response.additional_properties = d + return api_key_delete_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_key_list_response.py b/omni_python_sdk/models/api_key_list_response.py new file mode 100644 index 0000000..ba8aa17 --- /dev/null +++ b/omni_python_sdk/models/api_key_list_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.api_key import ApiKey + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="ApiKeyListResponse") + + +@_attrs_define +class ApiKeyListResponse: + """ + Attributes: + page_info (PageInfo): + records (list[ApiKey]): + """ + + page_info: PageInfo + records: list[ApiKey] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.api_key import ApiKey + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = ApiKey.from_dict(records_item_data) + + records.append(records_item) + + api_key_list_response = cls( + page_info=page_info, + records=records, + ) + + api_key_list_response.additional_properties = d + return api_key_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/api_key_type.py b/omni_python_sdk/models/api_key_type.py new file mode 100644 index 0000000..f9c6ab4 --- /dev/null +++ b/omni_python_sdk/models/api_key_type.py @@ -0,0 +1,15 @@ +from typing import Literal + +ApiKeyType = Literal["mcp", "organization", "personal"] + +API_KEY_TYPE_VALUES: set[ApiKeyType] = { + "mcp", + "organization", + "personal", +} + + +def check_api_key_type(value: str) -> ApiKeyType: + if value in API_KEY_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {API_KEY_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/api_key_update_body.py b/omni_python_sdk/models/api_key_update_body.py new file mode 100644 index 0000000..d83776d --- /dev/null +++ b/omni_python_sdk/models/api_key_update_body.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define + +T = TypeVar("T", bound="ApiKeyUpdateBody") + + +@_attrs_define +class ApiKeyUpdateBody: + """ + Attributes: + enabled (bool): Set to `false` to disable the token, `true` to re-enable it. + """ + + enabled: bool + + def to_dict(self) -> dict[str, Any]: + enabled = self.enabled + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "enabled": enabled, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + enabled = d.pop("enabled") + + api_key_update_body = cls( + enabled=enabled, + ) + + return api_key_update_body diff --git a/omni_python_sdk/models/api_keys_list_sort_direction.py b/omni_python_sdk/models/api_keys_list_sort_direction.py new file mode 100644 index 0000000..a020d6d --- /dev/null +++ b/omni_python_sdk/models/api_keys_list_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +ApiKeysListSortDirection = Literal["asc", "desc"] + +API_KEYS_LIST_SORT_DIRECTION_VALUES: set[ApiKeysListSortDirection] = { + "asc", + "desc", +} + + +def check_api_keys_list_sort_direction(value: str) -> ApiKeysListSortDirection: + if value in API_KEYS_LIST_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {API_KEYS_LIST_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/api_keys_list_sort_field.py b/omni_python_sdk/models/api_keys_list_sort_field.py new file mode 100644 index 0000000..93db297 --- /dev/null +++ b/omni_python_sdk/models/api_keys_list_sort_field.py @@ -0,0 +1,14 @@ +from typing import Literal + +ApiKeysListSortField = Literal["createdAt", "name"] + +API_KEYS_LIST_SORT_FIELD_VALUES: set[ApiKeysListSortField] = { + "createdAt", + "name", +} + + +def check_api_keys_list_sort_field(value: str) -> ApiKeysListSortField: + if value in API_KEYS_LIST_SORT_FIELD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {API_KEYS_LIST_SORT_FIELD_VALUES!r}") diff --git a/omni_python_sdk/models/api_keys_list_type.py b/omni_python_sdk/models/api_keys_list_type.py new file mode 100644 index 0000000..a5cfe29 --- /dev/null +++ b/omni_python_sdk/models/api_keys_list_type.py @@ -0,0 +1,15 @@ +from typing import Literal + +ApiKeysListType = Literal["mcp", "organization", "personal"] + +API_KEYS_LIST_TYPE_VALUES: set[ApiKeysListType] = { + "mcp", + "organization", + "personal", +} + + +def check_api_keys_list_type(value: str) -> ApiKeysListType: + if value in API_KEYS_LIST_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {API_KEYS_LIST_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/api_vis_config.py b/omni_python_sdk/models/api_vis_config.py new file mode 100644 index 0000000..d40e095 --- /dev/null +++ b/omni_python_sdk/models/api_vis_config.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ApiVisConfig") + + +@_attrs_define +class ApiVisConfig: + """Visualization configuration (Not statically modeled; use plain dicts.)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + api_vis_config = cls() + + api_vis_config.additional_properties = d + return api_vis_config + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/composite_filter.py b/omni_python_sdk/models/composite_filter.py new file mode 100644 index 0000000..1991a5a --- /dev/null +++ b/omni_python_sdk/models/composite_filter.py @@ -0,0 +1,257 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.composite_filter_conjunction import CompositeFilterConjunction, check_composite_filter_conjunction +from ..models.composite_filter_type import CompositeFilterType, check_composite_filter_type +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.composite_filter_filters_item_type_0 import CompositeFilterFiltersItemType0 + from ..models.composite_filter_filters_item_type_1 import CompositeFilterFiltersItemType1 + from ..models.composite_filter_filters_item_type_2 import CompositeFilterFiltersItemType2 + from ..models.composite_filter_filters_item_type_3 import CompositeFilterFiltersItemType3 + from ..models.composite_filter_filters_item_type_4 import CompositeFilterFiltersItemType4 + from ..models.composite_filter_filters_item_type_5 import CompositeFilterFiltersItemType5 + from ..models.composite_filter_filters_item_type_6 import CompositeFilterFiltersItemType6 + + +T = TypeVar("T", bound="CompositeFilter") + + +@_attrs_define +class CompositeFilter: + """ + Attributes: + conjunction (CompositeFilterConjunction): + filters (list[CompositeFilter | CompositeFilterFiltersItemType0 | CompositeFilterFiltersItemType1 | + CompositeFilterFiltersItemType2 | CompositeFilterFiltersItemType3 | CompositeFilterFiltersItemType4 | + CompositeFilterFiltersItemType5 | CompositeFilterFiltersItemType6]): Child filters — each a simple filter or + another composite filter. Recursive; see the dashboard-filters reference for the full grammar. + type_ (CompositeFilterType): + cancel_query_filter (bool | Unset): + ignore_if_unjoinable (bool | Unset): + is_negative (bool | None | Unset): + """ + + conjunction: CompositeFilterConjunction + filters: list[ + CompositeFilter + | CompositeFilterFiltersItemType0 + | CompositeFilterFiltersItemType1 + | CompositeFilterFiltersItemType2 + | CompositeFilterFiltersItemType3 + | CompositeFilterFiltersItemType4 + | CompositeFilterFiltersItemType5 + | CompositeFilterFiltersItemType6 + ] + type_: CompositeFilterType + cancel_query_filter: bool | Unset = UNSET + ignore_if_unjoinable: bool | Unset = UNSET + is_negative: bool | None | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.composite_filter_filters_item_type_0 import CompositeFilterFiltersItemType0 + from ..models.composite_filter_filters_item_type_1 import CompositeFilterFiltersItemType1 + from ..models.composite_filter_filters_item_type_2 import CompositeFilterFiltersItemType2 + from ..models.composite_filter_filters_item_type_3 import CompositeFilterFiltersItemType3 + from ..models.composite_filter_filters_item_type_4 import CompositeFilterFiltersItemType4 + from ..models.composite_filter_filters_item_type_5 import CompositeFilterFiltersItemType5 + from ..models.composite_filter_filters_item_type_6 import CompositeFilterFiltersItemType6 + + conjunction: str = self.conjunction + + filters = [] + for filters_item_data in self.filters: + filters_item: dict[str, Any] + if isinstance(filters_item_data, CompositeFilterFiltersItemType0): + filters_item = filters_item_data.to_dict() + elif isinstance(filters_item_data, CompositeFilterFiltersItemType1): + filters_item = filters_item_data.to_dict() + elif isinstance(filters_item_data, CompositeFilterFiltersItemType2): + filters_item = filters_item_data.to_dict() + elif isinstance(filters_item_data, CompositeFilterFiltersItemType3): + filters_item = filters_item_data.to_dict() + elif isinstance(filters_item_data, CompositeFilterFiltersItemType4): + filters_item = filters_item_data.to_dict() + elif isinstance(filters_item_data, CompositeFilterFiltersItemType5): + filters_item = filters_item_data.to_dict() + elif isinstance(filters_item_data, CompositeFilterFiltersItemType6): + filters_item = filters_item_data.to_dict() + else: + filters_item = filters_item_data.to_dict() + + filters.append(filters_item) + + type_: str = self.type_ + + cancel_query_filter = self.cancel_query_filter + + ignore_if_unjoinable = self.ignore_if_unjoinable + + is_negative: bool | None | Unset + if isinstance(self.is_negative, Unset): + is_negative = UNSET + else: + is_negative = self.is_negative + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "conjunction": conjunction, + "filters": filters, + "type": type_, + } + ) + if cancel_query_filter is not UNSET: + field_dict["cancel_query_filter"] = cancel_query_filter + if ignore_if_unjoinable is not UNSET: + field_dict["ignore_if_unjoinable"] = ignore_if_unjoinable + if is_negative is not UNSET: + field_dict["is_negative"] = is_negative + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.composite_filter_filters_item_type_0 import CompositeFilterFiltersItemType0 + from ..models.composite_filter_filters_item_type_1 import CompositeFilterFiltersItemType1 + from ..models.composite_filter_filters_item_type_2 import CompositeFilterFiltersItemType2 + from ..models.composite_filter_filters_item_type_3 import CompositeFilterFiltersItemType3 + from ..models.composite_filter_filters_item_type_4 import CompositeFilterFiltersItemType4 + from ..models.composite_filter_filters_item_type_5 import CompositeFilterFiltersItemType5 + from ..models.composite_filter_filters_item_type_6 import CompositeFilterFiltersItemType6 + + d = dict(src_dict) + conjunction = check_composite_filter_conjunction(d.pop("conjunction")) + + filters = [] + _filters = d.pop("filters") + for filters_item_data in _filters: + + def _parse_filters_item( + data: object, + ) -> ( + CompositeFilter + | CompositeFilterFiltersItemType0 + | CompositeFilterFiltersItemType1 + | CompositeFilterFiltersItemType2 + | CompositeFilterFiltersItemType3 + | CompositeFilterFiltersItemType4 + | CompositeFilterFiltersItemType5 + | CompositeFilterFiltersItemType6 + ): + try: + if not isinstance(data, dict): + raise TypeError() + filters_item_type_0 = CompositeFilterFiltersItemType0.from_dict(data) + + return filters_item_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + filters_item_type_1 = CompositeFilterFiltersItemType1.from_dict(data) + + return filters_item_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + filters_item_type_2 = CompositeFilterFiltersItemType2.from_dict(data) + + return filters_item_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + filters_item_type_3 = CompositeFilterFiltersItemType3.from_dict(data) + + return filters_item_type_3 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + filters_item_type_4 = CompositeFilterFiltersItemType4.from_dict(data) + + return filters_item_type_4 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + filters_item_type_5 = CompositeFilterFiltersItemType5.from_dict(data) + + return filters_item_type_5 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + filters_item_type_6 = CompositeFilterFiltersItemType6.from_dict(data) + + return filters_item_type_6 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + filters_item_type_7 = CompositeFilter.from_dict(data) + + return filters_item_type_7 + + filters_item = _parse_filters_item(filters_item_data) + + filters.append(filters_item) + + type_ = check_composite_filter_type(d.pop("type")) + + cancel_query_filter = d.pop("cancel_query_filter", UNSET) + + ignore_if_unjoinable = d.pop("ignore_if_unjoinable", UNSET) + + def _parse_is_negative(data: object) -> bool | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(bool | None | Unset, data) + + is_negative = _parse_is_negative(d.pop("is_negative", UNSET)) + + composite_filter = cls( + conjunction=conjunction, + filters=filters, + type_=type_, + cancel_query_filter=cancel_query_filter, + ignore_if_unjoinable=ignore_if_unjoinable, + is_negative=is_negative, + ) + + composite_filter.additional_properties = d + return composite_filter + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/composite_filter_conjunction.py b/omni_python_sdk/models/composite_filter_conjunction.py new file mode 100644 index 0000000..f5d8964 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_conjunction.py @@ -0,0 +1,14 @@ +from typing import Literal + +CompositeFilterConjunction = Literal["AND", "OR"] + +COMPOSITE_FILTER_CONJUNCTION_VALUES: set[CompositeFilterConjunction] = { + "AND", + "OR", +} + + +def check_composite_filter_conjunction(value: str) -> CompositeFilterConjunction: + if value in COMPOSITE_FILTER_CONJUNCTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_CONJUNCTION_VALUES!r}") diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_0.py b/omni_python_sdk/models/composite_filter_filters_item_type_0.py new file mode 100644 index 0000000..dd6d301 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_0.py @@ -0,0 +1,160 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.composite_filter_filters_item_type_0_kind import ( + CompositeFilterFiltersItemType0Kind, + check_composite_filter_filters_item_type_0_kind, +) +from ..models.composite_filter_filters_item_type_0_type import ( + CompositeFilterFiltersItemType0Type, + check_composite_filter_filters_item_type_0_type, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.composite_filter_filters_item_type_0_applied_labels import ( + CompositeFilterFiltersItemType0AppliedLabels, + ) + + +T = TypeVar("T", bound="CompositeFilterFiltersItemType0") + + +@_attrs_define +class CompositeFilterFiltersItemType0: + """ + Attributes: + kind (CompositeFilterFiltersItemType0Kind): + type_ (CompositeFilterFiltersItemType0Type): + values (list[str]): + cancel_query_filter (bool | Unset): + ignore_if_unjoinable (bool | Unset): + applied_labels (CompositeFilterFiltersItemType0AppliedLabels | Unset): + case_insensitive (bool | Unset): + is_negative (bool | None | Unset): + """ + + kind: CompositeFilterFiltersItemType0Kind + type_: CompositeFilterFiltersItemType0Type + values: list[str] + cancel_query_filter: bool | Unset = UNSET + ignore_if_unjoinable: bool | Unset = UNSET + applied_labels: CompositeFilterFiltersItemType0AppliedLabels | Unset = UNSET + case_insensitive: bool | Unset = UNSET + is_negative: bool | None | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + kind: str = self.kind + + type_: str = self.type_ + + values = self.values + + cancel_query_filter = self.cancel_query_filter + + ignore_if_unjoinable = self.ignore_if_unjoinable + + applied_labels: dict[str, Any] | Unset = UNSET + if not isinstance(self.applied_labels, Unset): + applied_labels = self.applied_labels.to_dict() + + case_insensitive = self.case_insensitive + + is_negative: bool | None | Unset + if isinstance(self.is_negative, Unset): + is_negative = UNSET + else: + is_negative = self.is_negative + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "kind": kind, + "type": type_, + "values": values, + } + ) + if cancel_query_filter is not UNSET: + field_dict["cancel_query_filter"] = cancel_query_filter + if ignore_if_unjoinable is not UNSET: + field_dict["ignore_if_unjoinable"] = ignore_if_unjoinable + if applied_labels is not UNSET: + field_dict["appliedLabels"] = applied_labels + if case_insensitive is not UNSET: + field_dict["case_insensitive"] = case_insensitive + if is_negative is not UNSET: + field_dict["is_negative"] = is_negative + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.composite_filter_filters_item_type_0_applied_labels import ( + CompositeFilterFiltersItemType0AppliedLabels, + ) + + d = dict(src_dict) + kind = check_composite_filter_filters_item_type_0_kind(d.pop("kind")) + + type_ = check_composite_filter_filters_item_type_0_type(d.pop("type")) + + values = cast(list[str], d.pop("values")) + + cancel_query_filter = d.pop("cancel_query_filter", UNSET) + + ignore_if_unjoinable = d.pop("ignore_if_unjoinable", UNSET) + + _applied_labels = d.pop("appliedLabels", UNSET) + applied_labels: CompositeFilterFiltersItemType0AppliedLabels | Unset + if isinstance(_applied_labels, Unset): + applied_labels = UNSET + else: + applied_labels = CompositeFilterFiltersItemType0AppliedLabels.from_dict(_applied_labels) + + case_insensitive = d.pop("case_insensitive", UNSET) + + def _parse_is_negative(data: object) -> bool | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(bool | None | Unset, data) + + is_negative = _parse_is_negative(d.pop("is_negative", UNSET)) + + composite_filter_filters_item_type_0 = cls( + kind=kind, + type_=type_, + values=values, + cancel_query_filter=cancel_query_filter, + ignore_if_unjoinable=ignore_if_unjoinable, + applied_labels=applied_labels, + case_insensitive=case_insensitive, + is_negative=is_negative, + ) + + composite_filter_filters_item_type_0.additional_properties = d + return composite_filter_filters_item_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_0_applied_labels.py b/omni_python_sdk/models/composite_filter_filters_item_type_0_applied_labels.py new file mode 100644 index 0000000..4b53e35 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_0_applied_labels.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="CompositeFilterFiltersItemType0AppliedLabels") + + +@_attrs_define +class CompositeFilterFiltersItemType0AppliedLabels: + """ """ + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + composite_filter_filters_item_type_0_applied_labels = cls() + + composite_filter_filters_item_type_0_applied_labels.additional_properties = d + return composite_filter_filters_item_type_0_applied_labels + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_0_kind.py b/omni_python_sdk/models/composite_filter_filters_item_type_0_kind.py new file mode 100644 index 0000000..88f6f87 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_0_kind.py @@ -0,0 +1,18 @@ +from typing import Literal + +CompositeFilterFiltersItemType0Kind = Literal["CONTAINS", "ENDS_WITH", "EQUALS", "IS_EMPTY", "SQL_LIKE", "STARTS_WITH"] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_0_KIND_VALUES: set[CompositeFilterFiltersItemType0Kind] = { + "CONTAINS", + "ENDS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE", + "STARTS_WITH", +} + + +def check_composite_filter_filters_item_type_0_kind(value: str) -> CompositeFilterFiltersItemType0Kind: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_0_KIND_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_0_KIND_VALUES!r}") diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_0_type.py b/omni_python_sdk/models/composite_filter_filters_item_type_0_type.py new file mode 100644 index 0000000..40dd53a --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_0_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +CompositeFilterFiltersItemType0Type = Literal["string"] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_0_TYPE_VALUES: set[CompositeFilterFiltersItemType0Type] = { + "string", +} + + +def check_composite_filter_filters_item_type_0_type(value: str) -> CompositeFilterFiltersItemType0Type: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_0_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_0_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_1.py b/omni_python_sdk/models/composite_filter_filters_item_type_1.py new file mode 100644 index 0000000..4fea443 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_1.py @@ -0,0 +1,147 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.composite_filter_filters_item_type_1_kind import ( + CompositeFilterFiltersItemType1Kind, + check_composite_filter_filters_item_type_1_kind, +) +from ..models.composite_filter_filters_item_type_1_type import ( + CompositeFilterFiltersItemType1Type, + check_composite_filter_filters_item_type_1_type, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CompositeFilterFiltersItemType1") + + +@_attrs_define +class CompositeFilterFiltersItemType1: + """ + Attributes: + kind (CompositeFilterFiltersItemType1Kind): + type_ (CompositeFilterFiltersItemType1Type): + values (list[float | str]): + cancel_query_filter (bool | Unset): + ignore_if_unjoinable (bool | Unset): + is_inclusive (bool | Unset): + is_negative (bool | None | Unset): + """ + + kind: CompositeFilterFiltersItemType1Kind + type_: CompositeFilterFiltersItemType1Type + values: list[float | str] + cancel_query_filter: bool | Unset = UNSET + ignore_if_unjoinable: bool | Unset = UNSET + is_inclusive: bool | Unset = UNSET + is_negative: bool | None | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + kind: str = self.kind + + type_: str = self.type_ + + values = [] + for values_item_data in self.values: + values_item: float | str + values_item = values_item_data + values.append(values_item) + + cancel_query_filter = self.cancel_query_filter + + ignore_if_unjoinable = self.ignore_if_unjoinable + + is_inclusive = self.is_inclusive + + is_negative: bool | None | Unset + if isinstance(self.is_negative, Unset): + is_negative = UNSET + else: + is_negative = self.is_negative + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "kind": kind, + "type": type_, + "values": values, + } + ) + if cancel_query_filter is not UNSET: + field_dict["cancel_query_filter"] = cancel_query_filter + if ignore_if_unjoinable is not UNSET: + field_dict["ignore_if_unjoinable"] = ignore_if_unjoinable + if is_inclusive is not UNSET: + field_dict["is_inclusive"] = is_inclusive + if is_negative is not UNSET: + field_dict["is_negative"] = is_negative + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + kind = check_composite_filter_filters_item_type_1_kind(d.pop("kind")) + + type_ = check_composite_filter_filters_item_type_1_type(d.pop("type")) + + values = [] + _values = d.pop("values") + for values_item_data in _values: + + def _parse_values_item(data: object) -> float | str: + return cast(float | str, data) + + values_item = _parse_values_item(values_item_data) + + values.append(values_item) + + cancel_query_filter = d.pop("cancel_query_filter", UNSET) + + ignore_if_unjoinable = d.pop("ignore_if_unjoinable", UNSET) + + is_inclusive = d.pop("is_inclusive", UNSET) + + def _parse_is_negative(data: object) -> bool | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(bool | None | Unset, data) + + is_negative = _parse_is_negative(d.pop("is_negative", UNSET)) + + composite_filter_filters_item_type_1 = cls( + kind=kind, + type_=type_, + values=values, + cancel_query_filter=cancel_query_filter, + ignore_if_unjoinable=ignore_if_unjoinable, + is_inclusive=is_inclusive, + is_negative=is_negative, + ) + + composite_filter_filters_item_type_1.additional_properties = d + return composite_filter_filters_item_type_1 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_1_kind.py b/omni_python_sdk/models/composite_filter_filters_item_type_1_kind.py new file mode 100644 index 0000000..8b0c18e --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_1_kind.py @@ -0,0 +1,16 @@ +from typing import Literal + +CompositeFilterFiltersItemType1Kind = Literal["BETWEEN", "EQUALS", "GREATER_THAN", "LESS_THAN"] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_1_KIND_VALUES: set[CompositeFilterFiltersItemType1Kind] = { + "BETWEEN", + "EQUALS", + "GREATER_THAN", + "LESS_THAN", +} + + +def check_composite_filter_filters_item_type_1_kind(value: str) -> CompositeFilterFiltersItemType1Kind: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_1_KIND_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_1_KIND_VALUES!r}") diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_1_type.py b/omni_python_sdk/models/composite_filter_filters_item_type_1_type.py new file mode 100644 index 0000000..5943b13 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_1_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +CompositeFilterFiltersItemType1Type = Literal["number"] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_1_TYPE_VALUES: set[CompositeFilterFiltersItemType1Type] = { + "number", +} + + +def check_composite_filter_filters_item_type_1_type(value: str) -> CompositeFilterFiltersItemType1Type: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_1_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_1_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_2.py b/omni_python_sdk/models/composite_filter_filters_item_type_2.py new file mode 100644 index 0000000..7b8315e --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_2.py @@ -0,0 +1,270 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.composite_filter_filters_item_type_2_kind import ( + CompositeFilterFiltersItemType2Kind, + check_composite_filter_filters_item_type_2_kind, +) +from ..models.composite_filter_filters_item_type_2_type import ( + CompositeFilterFiltersItemType2Type, + check_composite_filter_filters_item_type_2_type, +) +from ..models.composite_filter_filters_item_type_2_ui_type_type_1 import ( + CompositeFilterFiltersItemType2UiTypeType1, + check_composite_filter_filters_item_type_2_ui_type_type_1, +) +from ..models.composite_filter_filters_item_type_2_ui_type_type_2_type_1 import ( + CompositeFilterFiltersItemType2UiTypeType2Type1, + check_composite_filter_filters_item_type_2_ui_type_type_2_type_1, +) +from ..models.composite_filter_filters_item_type_2_ui_type_type_3_type_1 import ( + CompositeFilterFiltersItemType2UiTypeType3Type1, + check_composite_filter_filters_item_type_2_ui_type_type_3_type_1, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CompositeFilterFiltersItemType2") + + +@_attrs_define +class CompositeFilterFiltersItemType2: + """ + Attributes: + kind (CompositeFilterFiltersItemType2Kind): + type_ (CompositeFilterFiltersItemType2Type): + cancel_query_filter (bool | Unset): + ignore_if_unjoinable (bool | Unset): + is_fiscal (bool | Unset): + is_negative (bool | None | Unset): + left_side (None | str | Unset): + offset_interval_string (None | str | Unset): + right_side (None | str | Unset): + ui_type (CompositeFilterFiltersItemType2UiTypeType1 | CompositeFilterFiltersItemType2UiTypeType2Type1 | + CompositeFilterFiltersItemType2UiTypeType3Type1 | None | Unset): + """ + + kind: CompositeFilterFiltersItemType2Kind + type_: CompositeFilterFiltersItemType2Type + cancel_query_filter: bool | Unset = UNSET + ignore_if_unjoinable: bool | Unset = UNSET + is_fiscal: bool | Unset = UNSET + is_negative: bool | None | Unset = UNSET + left_side: None | str | Unset = UNSET + offset_interval_string: None | str | Unset = UNSET + right_side: None | str | Unset = UNSET + ui_type: ( + CompositeFilterFiltersItemType2UiTypeType1 + | CompositeFilterFiltersItemType2UiTypeType2Type1 + | CompositeFilterFiltersItemType2UiTypeType3Type1 + | None + | Unset + ) = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + kind: str = self.kind + + type_: str = self.type_ + + cancel_query_filter = self.cancel_query_filter + + ignore_if_unjoinable = self.ignore_if_unjoinable + + is_fiscal = self.is_fiscal + + is_negative: bool | None | Unset + if isinstance(self.is_negative, Unset): + is_negative = UNSET + else: + is_negative = self.is_negative + + left_side: None | str | Unset + if isinstance(self.left_side, Unset): + left_side = UNSET + else: + left_side = self.left_side + + offset_interval_string: None | str | Unset + if isinstance(self.offset_interval_string, Unset): + offset_interval_string = UNSET + else: + offset_interval_string = self.offset_interval_string + + right_side: None | str | Unset + if isinstance(self.right_side, Unset): + right_side = UNSET + else: + right_side = self.right_side + + ui_type: None | str | Unset + if isinstance(self.ui_type, Unset): + ui_type = UNSET + elif isinstance(self.ui_type, str): + ui_type = self.ui_type + elif isinstance(self.ui_type, str): + ui_type = self.ui_type + elif isinstance(self.ui_type, str): + ui_type = self.ui_type + else: + ui_type = self.ui_type + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "kind": kind, + "type": type_, + } + ) + if cancel_query_filter is not UNSET: + field_dict["cancel_query_filter"] = cancel_query_filter + if ignore_if_unjoinable is not UNSET: + field_dict["ignore_if_unjoinable"] = ignore_if_unjoinable + if is_fiscal is not UNSET: + field_dict["isFiscal"] = is_fiscal + if is_negative is not UNSET: + field_dict["is_negative"] = is_negative + if left_side is not UNSET: + field_dict["left_side"] = left_side + if offset_interval_string is not UNSET: + field_dict["offset_interval_string"] = offset_interval_string + if right_side is not UNSET: + field_dict["right_side"] = right_side + if ui_type is not UNSET: + field_dict["ui_type"] = ui_type + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + kind = check_composite_filter_filters_item_type_2_kind(d.pop("kind")) + + type_ = check_composite_filter_filters_item_type_2_type(d.pop("type")) + + cancel_query_filter = d.pop("cancel_query_filter", UNSET) + + ignore_if_unjoinable = d.pop("ignore_if_unjoinable", UNSET) + + is_fiscal = d.pop("isFiscal", UNSET) + + def _parse_is_negative(data: object) -> bool | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(bool | None | Unset, data) + + is_negative = _parse_is_negative(d.pop("is_negative", UNSET)) + + def _parse_left_side(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + left_side = _parse_left_side(d.pop("left_side", UNSET)) + + def _parse_offset_interval_string(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + offset_interval_string = _parse_offset_interval_string(d.pop("offset_interval_string", UNSET)) + + def _parse_right_side(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + right_side = _parse_right_side(d.pop("right_side", UNSET)) + + def _parse_ui_type( + data: object, + ) -> ( + CompositeFilterFiltersItemType2UiTypeType1 + | CompositeFilterFiltersItemType2UiTypeType2Type1 + | CompositeFilterFiltersItemType2UiTypeType3Type1 + | None + | Unset + ): + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + ui_type_type_1 = check_composite_filter_filters_item_type_2_ui_type_type_1(data) + + return ui_type_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, str): + raise TypeError() + ui_type_type_2_type_1 = check_composite_filter_filters_item_type_2_ui_type_type_2_type_1(data) + + return ui_type_type_2_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, str): + raise TypeError() + ui_type_type_3_type_1 = check_composite_filter_filters_item_type_2_ui_type_type_3_type_1(data) + + return ui_type_type_3_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast( + CompositeFilterFiltersItemType2UiTypeType1 + | CompositeFilterFiltersItemType2UiTypeType2Type1 + | CompositeFilterFiltersItemType2UiTypeType3Type1 + | None + | Unset, + data, + ) + + ui_type = _parse_ui_type(d.pop("ui_type", UNSET)) + + composite_filter_filters_item_type_2 = cls( + kind=kind, + type_=type_, + cancel_query_filter=cancel_query_filter, + ignore_if_unjoinable=ignore_if_unjoinable, + is_fiscal=is_fiscal, + is_negative=is_negative, + left_side=left_side, + offset_interval_string=offset_interval_string, + right_side=right_side, + ui_type=ui_type, + ) + + composite_filter_filters_item_type_2.additional_properties = d + return composite_filter_filters_item_type_2 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_2_kind.py b/omni_python_sdk/models/composite_filter_filters_item_type_2_kind.py new file mode 100644 index 0000000..ec9c59b --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_2_kind.py @@ -0,0 +1,41 @@ +from typing import Literal + +CompositeFilterFiltersItemType2Kind = Literal[ + "BEFORE", + "BETWEEN", + "IS_AT_HOUR_OF_DAY", + "IS_IN_MONTH_OF_YEAR", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "IS_ON_DAY_OF_QUARTER", + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_YEAR", + "ON_OR_AFTER", + "QUERY_OFFSET", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", +] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_KIND_VALUES: set[CompositeFilterFiltersItemType2Kind] = { + "BEFORE", + "BETWEEN", + "IS_AT_HOUR_OF_DAY", + "IS_IN_MONTH_OF_YEAR", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "IS_ON_DAY_OF_QUARTER", + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_YEAR", + "ON_OR_AFTER", + "QUERY_OFFSET", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", +} + + +def check_composite_filter_filters_item_type_2_kind(value: str) -> CompositeFilterFiltersItemType2Kind: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_KIND_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_KIND_VALUES!r}") diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_2_type.py b/omni_python_sdk/models/composite_filter_filters_item_type_2_type.py new file mode 100644 index 0000000..6d62c17 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_2_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +CompositeFilterFiltersItemType2Type = Literal["date"] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_TYPE_VALUES: set[CompositeFilterFiltersItemType2Type] = { + "date", +} + + +def check_composite_filter_filters_item_type_2_type(value: str) -> CompositeFilterFiltersItemType2Type: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_2_ui_type_type_1.py b/omni_python_sdk/models/composite_filter_filters_item_type_2_ui_type_type_1.py new file mode 100644 index 0000000..c1fd41a --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_2_ui_type_type_1.py @@ -0,0 +1,47 @@ +from typing import Literal + +CompositeFilterFiltersItemType2UiTypeType1 = Literal[ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "CUSTOM", + "DAY", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_ON_DAY_OF_WEEK", + "MONTH_OF_YEAR", + "ON_OR_AFTER", + "PAST", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "YEAR", +] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_UI_TYPE_TYPE_1_VALUES: set[CompositeFilterFiltersItemType2UiTypeType1] = { + "ANY_TIME", + "BEFORE", + "BETWEEN", + "CUSTOM", + "DAY", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_ON_DAY_OF_WEEK", + "MONTH_OF_YEAR", + "ON_OR_AFTER", + "PAST", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "YEAR", +} + + +def check_composite_filter_filters_item_type_2_ui_type_type_1(value: str) -> CompositeFilterFiltersItemType2UiTypeType1: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_UI_TYPE_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_UI_TYPE_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_2_ui_type_type_2_type_1.py b/omni_python_sdk/models/composite_filter_filters_item_type_2_ui_type_type_2_type_1.py new file mode 100644 index 0000000..7658efd --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_2_ui_type_type_2_type_1.py @@ -0,0 +1,51 @@ +from typing import Literal + +CompositeFilterFiltersItemType2UiTypeType2Type1 = Literal[ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "CUSTOM", + "DAY", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_ON_DAY_OF_WEEK", + "MONTH_OF_YEAR", + "ON_OR_AFTER", + "PAST", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "YEAR", +] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_UI_TYPE_TYPE_2_TYPE_1_VALUES: set[ + CompositeFilterFiltersItemType2UiTypeType2Type1 +] = { + "ANY_TIME", + "BEFORE", + "BETWEEN", + "CUSTOM", + "DAY", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_ON_DAY_OF_WEEK", + "MONTH_OF_YEAR", + "ON_OR_AFTER", + "PAST", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "YEAR", +} + + +def check_composite_filter_filters_item_type_2_ui_type_type_2_type_1( + value: str, +) -> CompositeFilterFiltersItemType2UiTypeType2Type1: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_UI_TYPE_TYPE_2_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_UI_TYPE_TYPE_2_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_2_ui_type_type_3_type_1.py b/omni_python_sdk/models/composite_filter_filters_item_type_2_ui_type_type_3_type_1.py new file mode 100644 index 0000000..565ac12 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_2_ui_type_type_3_type_1.py @@ -0,0 +1,51 @@ +from typing import Literal + +CompositeFilterFiltersItemType2UiTypeType3Type1 = Literal[ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "CUSTOM", + "DAY", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_ON_DAY_OF_WEEK", + "MONTH_OF_YEAR", + "ON_OR_AFTER", + "PAST", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "YEAR", +] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_UI_TYPE_TYPE_3_TYPE_1_VALUES: set[ + CompositeFilterFiltersItemType2UiTypeType3Type1 +] = { + "ANY_TIME", + "BEFORE", + "BETWEEN", + "CUSTOM", + "DAY", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_ON_DAY_OF_WEEK", + "MONTH_OF_YEAR", + "ON_OR_AFTER", + "PAST", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "YEAR", +} + + +def check_composite_filter_filters_item_type_2_ui_type_type_3_type_1( + value: str, +) -> CompositeFilterFiltersItemType2UiTypeType3Type1: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_UI_TYPE_TYPE_3_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_2_UI_TYPE_TYPE_3_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_3.py b/omni_python_sdk/models/composite_filter_filters_item_type_3.py new file mode 100644 index 0000000..81d2a1b --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_3.py @@ -0,0 +1,105 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.composite_filter_filters_item_type_3_type import ( + CompositeFilterFiltersItemType3Type, + check_composite_filter_filters_item_type_3_type, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CompositeFilterFiltersItemType3") + + +@_attrs_define +class CompositeFilterFiltersItemType3: + """ + Attributes: + type_ (CompositeFilterFiltersItemType3Type): + cancel_query_filter (bool | Unset): + ignore_if_unjoinable (bool | Unset): + is_negative (bool | None | Unset): + """ + + type_: CompositeFilterFiltersItemType3Type + cancel_query_filter: bool | Unset = UNSET + ignore_if_unjoinable: bool | Unset = UNSET + is_negative: bool | None | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_: str = self.type_ + + cancel_query_filter = self.cancel_query_filter + + ignore_if_unjoinable = self.ignore_if_unjoinable + + is_negative: bool | None | Unset + if isinstance(self.is_negative, Unset): + is_negative = UNSET + else: + is_negative = self.is_negative + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + } + ) + if cancel_query_filter is not UNSET: + field_dict["cancel_query_filter"] = cancel_query_filter + if ignore_if_unjoinable is not UNSET: + field_dict["ignore_if_unjoinable"] = ignore_if_unjoinable + if is_negative is not UNSET: + field_dict["is_negative"] = is_negative + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + type_ = check_composite_filter_filters_item_type_3_type(d.pop("type")) + + cancel_query_filter = d.pop("cancel_query_filter", UNSET) + + ignore_if_unjoinable = d.pop("ignore_if_unjoinable", UNSET) + + def _parse_is_negative(data: object) -> bool | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(bool | None | Unset, data) + + is_negative = _parse_is_negative(d.pop("is_negative", UNSET)) + + composite_filter_filters_item_type_3 = cls( + type_=type_, + cancel_query_filter=cancel_query_filter, + ignore_if_unjoinable=ignore_if_unjoinable, + is_negative=is_negative, + ) + + composite_filter_filters_item_type_3.additional_properties = d + return composite_filter_filters_item_type_3 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_3_type.py b/omni_python_sdk/models/composite_filter_filters_item_type_3_type.py new file mode 100644 index 0000000..eddf708 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_3_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +CompositeFilterFiltersItemType3Type = Literal["null"] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_3_TYPE_VALUES: set[CompositeFilterFiltersItemType3Type] = { + "null", +} + + +def check_composite_filter_filters_item_type_3_type(value: str) -> CompositeFilterFiltersItemType3Type: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_3_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_3_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_4.py b/omni_python_sdk/models/composite_filter_filters_item_type_4.py new file mode 100644 index 0000000..ea2b936 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_4.py @@ -0,0 +1,114 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.composite_filter_filters_item_type_4_type import ( + CompositeFilterFiltersItemType4Type, + check_composite_filter_filters_item_type_4_type, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CompositeFilterFiltersItemType4") + + +@_attrs_define +class CompositeFilterFiltersItemType4: + """ + Attributes: + type_ (CompositeFilterFiltersItemType4Type): + cancel_query_filter (bool | Unset): + ignore_if_unjoinable (bool | Unset): + is_negative (bool | None | Unset): + treat_nulls_as_false (bool | Unset): + """ + + type_: CompositeFilterFiltersItemType4Type + cancel_query_filter: bool | Unset = UNSET + ignore_if_unjoinable: bool | Unset = UNSET + is_negative: bool | None | Unset = UNSET + treat_nulls_as_false: bool | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_: str = self.type_ + + cancel_query_filter = self.cancel_query_filter + + ignore_if_unjoinable = self.ignore_if_unjoinable + + is_negative: bool | None | Unset + if isinstance(self.is_negative, Unset): + is_negative = UNSET + else: + is_negative = self.is_negative + + treat_nulls_as_false = self.treat_nulls_as_false + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + } + ) + if cancel_query_filter is not UNSET: + field_dict["cancel_query_filter"] = cancel_query_filter + if ignore_if_unjoinable is not UNSET: + field_dict["ignore_if_unjoinable"] = ignore_if_unjoinable + if is_negative is not UNSET: + field_dict["is_negative"] = is_negative + if treat_nulls_as_false is not UNSET: + field_dict["treat_nulls_as_false"] = treat_nulls_as_false + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + type_ = check_composite_filter_filters_item_type_4_type(d.pop("type")) + + cancel_query_filter = d.pop("cancel_query_filter", UNSET) + + ignore_if_unjoinable = d.pop("ignore_if_unjoinable", UNSET) + + def _parse_is_negative(data: object) -> bool | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(bool | None | Unset, data) + + is_negative = _parse_is_negative(d.pop("is_negative", UNSET)) + + treat_nulls_as_false = d.pop("treat_nulls_as_false", UNSET) + + composite_filter_filters_item_type_4 = cls( + type_=type_, + cancel_query_filter=cancel_query_filter, + ignore_if_unjoinable=ignore_if_unjoinable, + is_negative=is_negative, + treat_nulls_as_false=treat_nulls_as_false, + ) + + composite_filter_filters_item_type_4.additional_properties = d + return composite_filter_filters_item_type_4 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_4_type.py b/omni_python_sdk/models/composite_filter_filters_item_type_4_type.py new file mode 100644 index 0000000..d8a2814 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_4_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +CompositeFilterFiltersItemType4Type = Literal["boolean"] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_4_TYPE_VALUES: set[CompositeFilterFiltersItemType4Type] = { + "boolean", +} + + +def check_composite_filter_filters_item_type_4_type(value: str) -> CompositeFilterFiltersItemType4Type: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_4_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_4_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_5.py b/omni_python_sdk/models/composite_filter_filters_item_type_5.py new file mode 100644 index 0000000..ef6e36b --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_5.py @@ -0,0 +1,154 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.composite_filter_filters_item_type_5_type import ( + CompositeFilterFiltersItemType5Type, + check_composite_filter_filters_item_type_5_type, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.composite_filter_filters_item_type_5_view_query import CompositeFilterFiltersItemType5ViewQuery + + +T = TypeVar("T", bound="CompositeFilterFiltersItemType5") + + +@_attrs_define +class CompositeFilterFiltersItemType5: + """ + Attributes: + type_ (CompositeFilterFiltersItemType5Type): + cancel_query_filter (bool | Unset): + ignore_if_unjoinable (bool | Unset): + disregard_limit (bool | Unset): + field_name (str | Unset): + is_negative (bool | None | Unset): + query_id (str | Unset): + view_query (CompositeFilterFiltersItemType5ViewQuery | Unset): + """ + + type_: CompositeFilterFiltersItemType5Type + cancel_query_filter: bool | Unset = UNSET + ignore_if_unjoinable: bool | Unset = UNSET + disregard_limit: bool | Unset = UNSET + field_name: str | Unset = UNSET + is_negative: bool | None | Unset = UNSET + query_id: str | Unset = UNSET + view_query: CompositeFilterFiltersItemType5ViewQuery | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_: str = self.type_ + + cancel_query_filter = self.cancel_query_filter + + ignore_if_unjoinable = self.ignore_if_unjoinable + + disregard_limit = self.disregard_limit + + field_name = self.field_name + + is_negative: bool | None | Unset + if isinstance(self.is_negative, Unset): + is_negative = UNSET + else: + is_negative = self.is_negative + + query_id = self.query_id + + view_query: dict[str, Any] | Unset = UNSET + if not isinstance(self.view_query, Unset): + view_query = self.view_query.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + } + ) + if cancel_query_filter is not UNSET: + field_dict["cancel_query_filter"] = cancel_query_filter + if ignore_if_unjoinable is not UNSET: + field_dict["ignore_if_unjoinable"] = ignore_if_unjoinable + if disregard_limit is not UNSET: + field_dict["disregard_limit"] = disregard_limit + if field_name is not UNSET: + field_dict["field_name"] = field_name + if is_negative is not UNSET: + field_dict["is_negative"] = is_negative + if query_id is not UNSET: + field_dict["query_id"] = query_id + if view_query is not UNSET: + field_dict["view_query"] = view_query + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.composite_filter_filters_item_type_5_view_query import CompositeFilterFiltersItemType5ViewQuery + + d = dict(src_dict) + type_ = check_composite_filter_filters_item_type_5_type(d.pop("type")) + + cancel_query_filter = d.pop("cancel_query_filter", UNSET) + + ignore_if_unjoinable = d.pop("ignore_if_unjoinable", UNSET) + + disregard_limit = d.pop("disregard_limit", UNSET) + + field_name = d.pop("field_name", UNSET) + + def _parse_is_negative(data: object) -> bool | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(bool | None | Unset, data) + + is_negative = _parse_is_negative(d.pop("is_negative", UNSET)) + + query_id = d.pop("query_id", UNSET) + + _view_query = d.pop("view_query", UNSET) + view_query: CompositeFilterFiltersItemType5ViewQuery | Unset + if isinstance(_view_query, Unset): + view_query = UNSET + else: + view_query = CompositeFilterFiltersItemType5ViewQuery.from_dict(_view_query) + + composite_filter_filters_item_type_5 = cls( + type_=type_, + cancel_query_filter=cancel_query_filter, + ignore_if_unjoinable=ignore_if_unjoinable, + disregard_limit=disregard_limit, + field_name=field_name, + is_negative=is_negative, + query_id=query_id, + view_query=view_query, + ) + + composite_filter_filters_item_type_5.additional_properties = d + return composite_filter_filters_item_type_5 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_5_type.py b/omni_python_sdk/models/composite_filter_filters_item_type_5_type.py new file mode 100644 index 0000000..aa236dc --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_5_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +CompositeFilterFiltersItemType5Type = Literal["query"] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_5_TYPE_VALUES: set[CompositeFilterFiltersItemType5Type] = { + "query", +} + + +def check_composite_filter_filters_item_type_5_type(value: str) -> CompositeFilterFiltersItemType5Type: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_5_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_5_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_5_view_query.py b/omni_python_sdk/models/composite_filter_filters_item_type_5_view_query.py new file mode 100644 index 0000000..23f2557 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_5_view_query.py @@ -0,0 +1,118 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.composite_filter_filters_item_type_5_view_query_filters import ( + CompositeFilterFiltersItemType5ViewQueryFilters, + ) + + +T = TypeVar("T", bound="CompositeFilterFiltersItemType5ViewQuery") + + +@_attrs_define +class CompositeFilterFiltersItemType5ViewQuery: + """ + Attributes: + fields (list[str]): + filters (CompositeFilterFiltersItemType5ViewQueryFilters | Unset): + limit (float | Unset): + sorts (list[Any] | Unset): + table (str | Unset): + """ + + fields: list[str] + filters: CompositeFilterFiltersItemType5ViewQueryFilters | Unset = UNSET + limit: float | Unset = UNSET + sorts: list[Any] | Unset = UNSET + table: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + fields = self.fields + + filters: dict[str, Any] | Unset = UNSET + if not isinstance(self.filters, Unset): + filters = self.filters.to_dict() + + limit = self.limit + + sorts: list[Any] | Unset = UNSET + if not isinstance(self.sorts, Unset): + sorts = self.sorts + + table = self.table + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "fields": fields, + } + ) + if filters is not UNSET: + field_dict["filters"] = filters + if limit is not UNSET: + field_dict["limit"] = limit + if sorts is not UNSET: + field_dict["sorts"] = sorts + if table is not UNSET: + field_dict["table"] = table + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.composite_filter_filters_item_type_5_view_query_filters import ( + CompositeFilterFiltersItemType5ViewQueryFilters, + ) + + d = dict(src_dict) + fields = cast(list[str], d.pop("fields")) + + _filters = d.pop("filters", UNSET) + filters: CompositeFilterFiltersItemType5ViewQueryFilters | Unset + if isinstance(_filters, Unset): + filters = UNSET + else: + filters = CompositeFilterFiltersItemType5ViewQueryFilters.from_dict(_filters) + + limit = d.pop("limit", UNSET) + + sorts = cast(list[Any], d.pop("sorts", UNSET)) + + table = d.pop("table", UNSET) + + composite_filter_filters_item_type_5_view_query = cls( + fields=fields, + filters=filters, + limit=limit, + sorts=sorts, + table=table, + ) + + composite_filter_filters_item_type_5_view_query.additional_properties = d + return composite_filter_filters_item_type_5_view_query + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_5_view_query_filters.py b/omni_python_sdk/models/composite_filter_filters_item_type_5_view_query_filters.py new file mode 100644 index 0000000..eb95707 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_5_view_query_filters.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="CompositeFilterFiltersItemType5ViewQueryFilters") + + +@_attrs_define +class CompositeFilterFiltersItemType5ViewQueryFilters: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + composite_filter_filters_item_type_5_view_query_filters = cls() + + composite_filter_filters_item_type_5_view_query_filters.additional_properties = d + return composite_filter_filters_item_type_5_view_query_filters + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_6.py b/omni_python_sdk/models/composite_filter_filters_item_type_6.py new file mode 100644 index 0000000..5b8f460 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_6.py @@ -0,0 +1,93 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.composite_filter_filters_item_type_6_type import ( + CompositeFilterFiltersItemType6Type, + check_composite_filter_filters_item_type_6_type, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="CompositeFilterFiltersItemType6") + + +@_attrs_define +class CompositeFilterFiltersItemType6: + """ + Attributes: + type_ (CompositeFilterFiltersItemType6Type): + user_attribute_name (str): + cancel_query_filter (bool | Unset): + ignore_if_unjoinable (bool | Unset): + """ + + type_: CompositeFilterFiltersItemType6Type + user_attribute_name: str + cancel_query_filter: bool | Unset = UNSET + ignore_if_unjoinable: bool | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_: str = self.type_ + + user_attribute_name = self.user_attribute_name + + cancel_query_filter = self.cancel_query_filter + + ignore_if_unjoinable = self.ignore_if_unjoinable + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + "user_attribute_name": user_attribute_name, + } + ) + if cancel_query_filter is not UNSET: + field_dict["cancel_query_filter"] = cancel_query_filter + if ignore_if_unjoinable is not UNSET: + field_dict["ignore_if_unjoinable"] = ignore_if_unjoinable + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + type_ = check_composite_filter_filters_item_type_6_type(d.pop("type")) + + user_attribute_name = d.pop("user_attribute_name") + + cancel_query_filter = d.pop("cancel_query_filter", UNSET) + + ignore_if_unjoinable = d.pop("ignore_if_unjoinable", UNSET) + + composite_filter_filters_item_type_6 = cls( + type_=type_, + user_attribute_name=user_attribute_name, + cancel_query_filter=cancel_query_filter, + ignore_if_unjoinable=ignore_if_unjoinable, + ) + + composite_filter_filters_item_type_6.additional_properties = d + return composite_filter_filters_item_type_6 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/composite_filter_filters_item_type_6_type.py b/omni_python_sdk/models/composite_filter_filters_item_type_6_type.py new file mode 100644 index 0000000..2d1b6e2 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_filters_item_type_6_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +CompositeFilterFiltersItemType6Type = Literal["user_attribute"] + +COMPOSITE_FILTER_FILTERS_ITEM_TYPE_6_TYPE_VALUES: set[CompositeFilterFiltersItemType6Type] = { + "user_attribute", +} + + +def check_composite_filter_filters_item_type_6_type(value: str) -> CompositeFilterFiltersItemType6Type: + if value in COMPOSITE_FILTER_FILTERS_ITEM_TYPE_6_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_FILTERS_ITEM_TYPE_6_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/composite_filter_type.py b/omni_python_sdk/models/composite_filter_type.py new file mode 100644 index 0000000..9e4c446 --- /dev/null +++ b/omni_python_sdk/models/composite_filter_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +CompositeFilterType = Literal["composite"] + +COMPOSITE_FILTER_TYPE_VALUES: set[CompositeFilterType] = { + "composite", +} + + +def check_composite_filter_type(value: str) -> CompositeFilterType: + if value in COMPOSITE_FILTER_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {COMPOSITE_FILTER_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/connection_environments_create_connections_environments_create_body.py b/omni_python_sdk/models/connection_environments_create_connections_environments_create_body.py new file mode 100644 index 0000000..9a6fb86 --- /dev/null +++ b/omni_python_sdk/models/connection_environments_create_connections_environments_create_body.py @@ -0,0 +1,80 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody") + + +@_attrs_define +class ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateBody: + """Request body for creating connection environments + + Attributes: + base_connection_id (UUID): ID of the base connection Example: 550e8400-e29b-41d4-a716-446655440000. + environment_connection_ids (list[UUID]): IDs of connections to use as environments Example: + ['550e8400-e29b-41d4-a716-446655440002', '550e8400-e29b-41d4-a716-446655440003']. + """ + + base_connection_id: UUID + environment_connection_ids: list[UUID] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + base_connection_id = str(self.base_connection_id) + + environment_connection_ids = [] + for environment_connection_ids_item_data in self.environment_connection_ids: + environment_connection_ids_item = str(environment_connection_ids_item_data) + environment_connection_ids.append(environment_connection_ids_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "baseConnectionId": base_connection_id, + "environmentConnectionIds": environment_connection_ids, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + base_connection_id = UUID(d.pop("baseConnectionId")) + + environment_connection_ids = [] + _environment_connection_ids = d.pop("environmentConnectionIds") + for environment_connection_ids_item_data in _environment_connection_ids: + environment_connection_ids_item = UUID(environment_connection_ids_item_data) + + environment_connection_ids.append(environment_connection_ids_item) + + connection_environments_create_connections_environments_create_body = cls( + base_connection_id=base_connection_id, + environment_connection_ids=environment_connection_ids, + ) + + connection_environments_create_connections_environments_create_body.additional_properties = d + return connection_environments_create_connections_environments_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connection_environments_create_connections_environments_create_response.py b/omni_python_sdk/models/connection_environments_create_connections_environments_create_response.py new file mode 100644 index 0000000..1900b81 --- /dev/null +++ b/omni_python_sdk/models/connection_environments_create_connections_environments_create_response.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.connection_environments_create_connections_environments_create_response_connection_environment import ( + ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponseConnectionEnvironment, + ) + + +T = TypeVar("T", bound="ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse") + + +@_attrs_define +class ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponse: + """Create connection environments response + + Attributes: + connection_environments + (list[ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponseConnectionEnvironment]): Created + connection environments + """ + + connection_environments: list[ + ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponseConnectionEnvironment + ] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + connection_environments = [] + for connection_environments_item_data in self.connection_environments: + connection_environments_item = connection_environments_item_data.to_dict() + connection_environments.append(connection_environments_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "connectionEnvironments": connection_environments, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.connection_environments_create_connections_environments_create_response_connection_environment import ( + ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponseConnectionEnvironment, + ) + + d = dict(src_dict) + connection_environments = [] + _connection_environments = d.pop("connectionEnvironments") + for connection_environments_item_data in _connection_environments: + connection_environments_item = ( + ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponseConnectionEnvironment.from_dict( + connection_environments_item_data + ) + ) + + connection_environments.append(connection_environments_item) + + connection_environments_create_connections_environments_create_response = cls( + connection_environments=connection_environments, + ) + + connection_environments_create_connections_environments_create_response.additional_properties = d + return connection_environments_create_connections_environments_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connection_environments_create_connections_environments_create_response_connection_environment.py b/omni_python_sdk/models/connection_environments_create_connections_environments_create_response_connection_environment.py new file mode 100644 index 0000000..1a5d9c8 --- /dev/null +++ b/omni_python_sdk/models/connection_environments_create_connections_environments_create_response_connection_environment.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponseConnectionEnvironment") + + +@_attrs_define +class ConnectionEnvironmentsCreateConnectionsEnvironmentsCreateResponseConnectionEnvironment: + """Connection environment object + + Attributes: + base_connection_id (UUID): ID of the base connection Example: 550e8400-e29b-41d4-a716-446655440000. + connection_id (UUID): ID of the environment connection Example: 550e8400-e29b-41d4-a716-446655440002. + id (UUID): Unique connection environment identifier Example: 550e8400-e29b-41d4-a716-446655440001. + user_attribute_values (list[str]): User attribute values for this environment Example: ['us-east', + 'production']. + """ + + base_connection_id: UUID + connection_id: UUID + id: UUID + user_attribute_values: list[str] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + base_connection_id = str(self.base_connection_id) + + connection_id = str(self.connection_id) + + id = str(self.id) + + user_attribute_values = self.user_attribute_values + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "baseConnectionId": base_connection_id, + "connectionId": connection_id, + "id": id, + "userAttributeValues": user_attribute_values, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + base_connection_id = UUID(d.pop("baseConnectionId")) + + connection_id = UUID(d.pop("connectionId")) + + id = UUID(d.pop("id")) + + user_attribute_values = cast(list[str], d.pop("userAttributeValues")) + + connection_environments_create_connections_environments_create_response_connection_environment = cls( + base_connection_id=base_connection_id, + connection_id=connection_id, + id=id, + user_attribute_values=user_attribute_values, + ) + + connection_environments_create_connections_environments_create_response_connection_environment.additional_properties = d + return connection_environments_create_connections_environments_create_response_connection_environment + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connection_environments_delete_connections_environments_delete_response.py b/omni_python_sdk/models/connection_environments_delete_connections_environments_delete_response.py new file mode 100644 index 0000000..2f15e52 --- /dev/null +++ b/omni_python_sdk/models/connection_environments_delete_connections_environments_delete_response.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse") + + +@_attrs_define +class ConnectionEnvironmentsDeleteConnectionsEnvironmentsDeleteResponse: + """Delete connection environment response + + Attributes: + success (bool): Whether the operation succeeded Example: True. + """ + + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + success = d.pop("success") + + connection_environments_delete_connections_environments_delete_response = cls( + success=success, + ) + + connection_environments_delete_connections_environments_delete_response.additional_properties = d + return connection_environments_delete_connections_environments_delete_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connection_environments_update_connections_environments_update_body.py b/omni_python_sdk/models/connection_environments_update_connections_environments_update_body.py new file mode 100644 index 0000000..ed5605b --- /dev/null +++ b/omni_python_sdk/models/connection_environments_update_connections_environments_update_body.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody") + + +@_attrs_define +class ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateBody: + """Request body for updating a connection environment + + Attributes: + user_attribute_values (list[str]): User attribute values for this environment Example: ['us-east', + 'production']. + """ + + user_attribute_values: list[str] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + user_attribute_values = self.user_attribute_values + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "userAttributeValues": user_attribute_values, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + user_attribute_values = cast(list[str], d.pop("userAttributeValues")) + + connection_environments_update_connections_environments_update_body = cls( + user_attribute_values=user_attribute_values, + ) + + connection_environments_update_connections_environments_update_body.additional_properties = d + return connection_environments_update_connections_environments_update_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connection_environments_update_connections_environments_update_response.py b/omni_python_sdk/models/connection_environments_update_connections_environments_update_response.py new file mode 100644 index 0000000..d74ac93 --- /dev/null +++ b/omni_python_sdk/models/connection_environments_update_connections_environments_update_response.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse") + + +@_attrs_define +class ConnectionEnvironmentsUpdateConnectionsEnvironmentsUpdateResponse: + """Update connection environment response + + Attributes: + success (bool): Whether the operation succeeded Example: True. + """ + + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + success = d.pop("success") + + connection_environments_update_connections_environments_update_response = cls( + success=success, + ) + + connection_environments_update_connections_environments_update_response.additional_properties = d + return connection_environments_update_connections_environments_update_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_create_connections_create_body.py b/omni_python_sdk/models/connections_create_connections_create_body.py new file mode 100644 index 0000000..02e2fd9 --- /dev/null +++ b/omni_python_sdk/models/connections_create_connections_create_body.py @@ -0,0 +1,476 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.connections_create_connections_create_body_base_role import ( + ConnectionsCreateConnectionsCreateBodyBaseRole, + check_connections_create_connections_create_body_base_role, +) +from ..models.connections_create_connections_create_body_dialect import ( + ConnectionsCreateConnectionsCreateBodyDialect, + check_connections_create_connections_create_body_dialect, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ConnectionsCreateConnectionsCreateBody") + + +@_attrs_define +class ConnectionsCreateConnectionsCreateBody: + """Request body for creating a database connection. Required fields: dialect, name, passwordUnencrypted. Additional + fields may be required depending on the dialect. + + Attributes: + dialect (ConnectionsCreateConnectionsCreateBodyDialect): The database dialect Example: snowflake. + name (str): A descriptive name for the connection Example: Production Warehouse. + password_unencrypted (str): The password to authenticate with. For BigQuery, this must be the JSON service + account key file content. For Snowflake with keypair authentication, this can be omitted. + accepts_license (bool | Unset): Acceptance of the license terms. Required for Oracle connections. Example: True. + allows_user_specific_timezones (bool | Unset): Whether to allow users to specify their own timezones Default: + False. + always_scope_view_names (bool | Unset): Whether to always include schema (and catalog) prefixes in generated + view names, even for tables in the default schema. Defaults to true for dialects that support multiple catalogs, + false otherwise. Example: True. + authentication_type (str | Unset): Authentication type. Applicable for BigQuery, MSSQL, Snowflake, Databricks, + and Athena. Example: snowflake-password. + aws_role_arn (str | Unset): AWS IAM role ARN. Applicable for Athena only. Example: + arn:aws:iam::123456789012:role/OmniAthenaRole. + base_role (ConnectionsCreateConnectionsCreateBodyBaseRole | Unset): The default role for users accessing the + connection Example: QUERIER. + database (str | Unset): The default database/catalog to connect to. For BigQuery, this is the project ID. For + Athena, this is the data catalog. Example: analytics_db. + default_schema (str | Unset): The default schema to use. Required for MSSQL. Example: public. + enable_db_semantic_layer_integration (bool | Unset): Enable the dialect-native semantic layer integration. + Applicable for Snowflake and Databricks. Default: False. + enable_db_semantic_layer_topics (bool | Unset): Enable the dialect-native semantic layer topics. Applicable for + Snowflake and Databricks. Default: False. + external_oauth_audience (str | Unset): External OAuth audience claim. Applicable for Snowflake. + external_oauth_authorization_url (str | Unset): External OAuth authorization URL (must be HTTPS). Applicable for + Snowflake. Example: https://oauth.example.com/authorize. + external_oauth_token_url (str | Unset): External OAuth token URL (must be HTTPS). Applicable for Snowflake. + Example: https://oauth.example.com/token. + host (str | Unset): The hostname or IP address of the database server. For Snowflake, provide only the account + identifier. Example: myaccount. + host_override (str | Unset): Custom Snowflake host (when not using the account identifier). Mutually exclusive + with `host`. Example: myaccount.snowflakecomputing.com. + include_other_catalogs (str | Unset): Comma-separated list of other catalogs/databases to include. Only + applicable for databases that support multi-catalog queries. Example: other_project1,other_project2. + include_schemas (str | Unset): Comma-separated list of schemas to include. Leave empty to include all schemas. + Example: public,analytics. + infer_relationships_from_column_names (bool | Unset): Whether to infer relationships from column-name + conventions during schema refresh. Defaults to true. Default: True. Example: True. + infer_relationships_from_foreign_keys (bool | Unset): Whether to infer relationships from declared foreign keys + during schema refresh. Currently honored for Postgres and Snowflake. Default: False. + max_billing_bytes (str | Unset): Maximum bytes that can be billed for a BigQuery query. Applicable for BigQuery + only. Example: 1000000000. + oauth_client_id (str | Unset): OAuth client ID for admin schema refresh. Applicable for Snowflake and + Databricks. + oauth_client_secret_unencrypted (str | Unset): OAuth client secret for admin schema refresh. Applicable for + Snowflake and Databricks. + offloaded_schemas (list[str] | str | Unset): Schemas whose tables should be queried via the offloaded engine. + Accepts a comma-separated string or an array of schema names. Example: ['analytics_archive']. + port (int | Unset): The port number for the database connection. Not required for Snowflake, MotherDuck, + BigQuery, Databricks, and Athena. Example: 5432. + private_key (str | Unset): An RSA key for keypair authentication. Omni will automatically add PEM headers if + none are provided. Applicable for Snowflake only. + query_timeout_seconds (int | Unset): The timeout in seconds for queries. Maximum value is 3600 (1 hour). Only + applicable for databases that support query timeouts. Example: 900. + query_timezone (str | Unset): The timezone to use for queries Example: NONE. + region (str | Unset): Required for BigQuery and Athena connections. For BigQuery, specify a region like "us". + For Athena, specify an AWS region like "us-east-1". Example: us-east-1. + scratch_schema (str | Unset): Schema to use for data input (upload) tables. If not specified, a suitable default + will be chosen. Example: omni_scratch. + system_timezone (str | Unset): The timezone to use for the system Example: UTC. + trust_server_certificate (bool | Unset): Whether to trust the server certificate. Applicable for MSSQL, Exasol, + ClickHouse, Trino, and SAP HANA. Default: False. + use_machine_auth (bool | Unset): Whether to authenticate using machine credentials (OAuth M2M). Applicable for + Athena and Databricks. + username (str | Unset): The username to authenticate with. For BigQuery, this is the client email from the + service account. Example: analytics_user. + warehouse (str | Unset): Required for Snowflake (specify the warehouse) and Databricks (specify the HTTP path). + May be omitted for Snowflake OAuth connections, in which case each user's Snowflake default warehouse applies. + Example: COMPUTE_WH. + wif_audience (str | Unset): Full resource name of the workload identity pool provider. Required for BigQuery + workload identity federation authentication. Example: + //iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider. + wif_service_account_email (str | Unset): Service account to impersonate for BigQuery workload identity + federation authentication. When omitted, the federated identity is used directly. Example: omni@my- + project.iam.gserviceaccount.com. + """ + + dialect: ConnectionsCreateConnectionsCreateBodyDialect + name: str + password_unencrypted: str + accepts_license: bool | Unset = UNSET + allows_user_specific_timezones: bool | Unset = False + always_scope_view_names: bool | Unset = UNSET + authentication_type: str | Unset = UNSET + aws_role_arn: str | Unset = UNSET + base_role: ConnectionsCreateConnectionsCreateBodyBaseRole | Unset = UNSET + database: str | Unset = UNSET + default_schema: str | Unset = UNSET + enable_db_semantic_layer_integration: bool | Unset = False + enable_db_semantic_layer_topics: bool | Unset = False + external_oauth_audience: str | Unset = UNSET + external_oauth_authorization_url: str | Unset = UNSET + external_oauth_token_url: str | Unset = UNSET + host: str | Unset = UNSET + host_override: str | Unset = UNSET + include_other_catalogs: str | Unset = UNSET + include_schemas: str | Unset = UNSET + infer_relationships_from_column_names: bool | Unset = True + infer_relationships_from_foreign_keys: bool | Unset = False + max_billing_bytes: str | Unset = UNSET + oauth_client_id: str | Unset = UNSET + oauth_client_secret_unencrypted: str | Unset = UNSET + offloaded_schemas: list[str] | str | Unset = UNSET + port: int | Unset = UNSET + private_key: str | Unset = UNSET + query_timeout_seconds: int | Unset = UNSET + query_timezone: str | Unset = UNSET + region: str | Unset = UNSET + scratch_schema: str | Unset = UNSET + system_timezone: str | Unset = UNSET + trust_server_certificate: bool | Unset = False + use_machine_auth: bool | Unset = UNSET + username: str | Unset = UNSET + warehouse: str | Unset = UNSET + wif_audience: str | Unset = UNSET + wif_service_account_email: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + dialect: str = self.dialect + + name = self.name + + password_unencrypted = self.password_unencrypted + + accepts_license = self.accepts_license + + allows_user_specific_timezones = self.allows_user_specific_timezones + + always_scope_view_names = self.always_scope_view_names + + authentication_type = self.authentication_type + + aws_role_arn = self.aws_role_arn + + base_role: str | Unset = UNSET + if not isinstance(self.base_role, Unset): + base_role = self.base_role + + database = self.database + + default_schema = self.default_schema + + enable_db_semantic_layer_integration = self.enable_db_semantic_layer_integration + + enable_db_semantic_layer_topics = self.enable_db_semantic_layer_topics + + external_oauth_audience = self.external_oauth_audience + + external_oauth_authorization_url = self.external_oauth_authorization_url + + external_oauth_token_url = self.external_oauth_token_url + + host = self.host + + host_override = self.host_override + + include_other_catalogs = self.include_other_catalogs + + include_schemas = self.include_schemas + + infer_relationships_from_column_names = self.infer_relationships_from_column_names + + infer_relationships_from_foreign_keys = self.infer_relationships_from_foreign_keys + + max_billing_bytes = self.max_billing_bytes + + oauth_client_id = self.oauth_client_id + + oauth_client_secret_unencrypted = self.oauth_client_secret_unencrypted + + offloaded_schemas: list[str] | str | Unset + if isinstance(self.offloaded_schemas, Unset): + offloaded_schemas = UNSET + elif isinstance(self.offloaded_schemas, list): + offloaded_schemas = self.offloaded_schemas + + else: + offloaded_schemas = self.offloaded_schemas + + port = self.port + + private_key = self.private_key + + query_timeout_seconds = self.query_timeout_seconds + + query_timezone = self.query_timezone + + region = self.region + + scratch_schema = self.scratch_schema + + system_timezone = self.system_timezone + + trust_server_certificate = self.trust_server_certificate + + use_machine_auth = self.use_machine_auth + + username = self.username + + warehouse = self.warehouse + + wif_audience = self.wif_audience + + wif_service_account_email = self.wif_service_account_email + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "dialect": dialect, + "name": name, + "passwordUnencrypted": password_unencrypted, + } + ) + if accepts_license is not UNSET: + field_dict["acceptsLicense"] = accepts_license + if allows_user_specific_timezones is not UNSET: + field_dict["allowsUserSpecificTimezones"] = allows_user_specific_timezones + if always_scope_view_names is not UNSET: + field_dict["alwaysScopeViewNames"] = always_scope_view_names + if authentication_type is not UNSET: + field_dict["authenticationType"] = authentication_type + if aws_role_arn is not UNSET: + field_dict["awsRoleArn"] = aws_role_arn + if base_role is not UNSET: + field_dict["baseRole"] = base_role + if database is not UNSET: + field_dict["database"] = database + if default_schema is not UNSET: + field_dict["defaultSchema"] = default_schema + if enable_db_semantic_layer_integration is not UNSET: + field_dict["enableDbSemanticLayerIntegration"] = enable_db_semantic_layer_integration + if enable_db_semantic_layer_topics is not UNSET: + field_dict["enableDbSemanticLayerTopics"] = enable_db_semantic_layer_topics + if external_oauth_audience is not UNSET: + field_dict["externalOauthAudience"] = external_oauth_audience + if external_oauth_authorization_url is not UNSET: + field_dict["externalOauthAuthorizationUrl"] = external_oauth_authorization_url + if external_oauth_token_url is not UNSET: + field_dict["externalOauthTokenUrl"] = external_oauth_token_url + if host is not UNSET: + field_dict["host"] = host + if host_override is not UNSET: + field_dict["hostOverride"] = host_override + if include_other_catalogs is not UNSET: + field_dict["includeOtherCatalogs"] = include_other_catalogs + if include_schemas is not UNSET: + field_dict["includeSchemas"] = include_schemas + if infer_relationships_from_column_names is not UNSET: + field_dict["inferRelationshipsFromColumnNames"] = infer_relationships_from_column_names + if infer_relationships_from_foreign_keys is not UNSET: + field_dict["inferRelationshipsFromForeignKeys"] = infer_relationships_from_foreign_keys + if max_billing_bytes is not UNSET: + field_dict["maxBillingBytes"] = max_billing_bytes + if oauth_client_id is not UNSET: + field_dict["oauthClientId"] = oauth_client_id + if oauth_client_secret_unencrypted is not UNSET: + field_dict["oauthClientSecretUnencrypted"] = oauth_client_secret_unencrypted + if offloaded_schemas is not UNSET: + field_dict["offloadedSchemas"] = offloaded_schemas + if port is not UNSET: + field_dict["port"] = port + if private_key is not UNSET: + field_dict["privateKey"] = private_key + if query_timeout_seconds is not UNSET: + field_dict["queryTimeoutSeconds"] = query_timeout_seconds + if query_timezone is not UNSET: + field_dict["queryTimezone"] = query_timezone + if region is not UNSET: + field_dict["region"] = region + if scratch_schema is not UNSET: + field_dict["scratchSchema"] = scratch_schema + if system_timezone is not UNSET: + field_dict["systemTimezone"] = system_timezone + if trust_server_certificate is not UNSET: + field_dict["trustServerCertificate"] = trust_server_certificate + if use_machine_auth is not UNSET: + field_dict["useMachineAuth"] = use_machine_auth + if username is not UNSET: + field_dict["username"] = username + if warehouse is not UNSET: + field_dict["warehouse"] = warehouse + if wif_audience is not UNSET: + field_dict["wifAudience"] = wif_audience + if wif_service_account_email is not UNSET: + field_dict["wifServiceAccountEmail"] = wif_service_account_email + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + dialect = check_connections_create_connections_create_body_dialect(d.pop("dialect")) + + name = d.pop("name") + + password_unencrypted = d.pop("passwordUnencrypted") + + accepts_license = d.pop("acceptsLicense", UNSET) + + allows_user_specific_timezones = d.pop("allowsUserSpecificTimezones", UNSET) + + always_scope_view_names = d.pop("alwaysScopeViewNames", UNSET) + + authentication_type = d.pop("authenticationType", UNSET) + + aws_role_arn = d.pop("awsRoleArn", UNSET) + + _base_role = d.pop("baseRole", UNSET) + base_role: ConnectionsCreateConnectionsCreateBodyBaseRole | Unset + if isinstance(_base_role, Unset): + base_role = UNSET + else: + base_role = check_connections_create_connections_create_body_base_role(_base_role) + + database = d.pop("database", UNSET) + + default_schema = d.pop("defaultSchema", UNSET) + + enable_db_semantic_layer_integration = d.pop("enableDbSemanticLayerIntegration", UNSET) + + enable_db_semantic_layer_topics = d.pop("enableDbSemanticLayerTopics", UNSET) + + external_oauth_audience = d.pop("externalOauthAudience", UNSET) + + external_oauth_authorization_url = d.pop("externalOauthAuthorizationUrl", UNSET) + + external_oauth_token_url = d.pop("externalOauthTokenUrl", UNSET) + + host = d.pop("host", UNSET) + + host_override = d.pop("hostOverride", UNSET) + + include_other_catalogs = d.pop("includeOtherCatalogs", UNSET) + + include_schemas = d.pop("includeSchemas", UNSET) + + infer_relationships_from_column_names = d.pop("inferRelationshipsFromColumnNames", UNSET) + + infer_relationships_from_foreign_keys = d.pop("inferRelationshipsFromForeignKeys", UNSET) + + max_billing_bytes = d.pop("maxBillingBytes", UNSET) + + oauth_client_id = d.pop("oauthClientId", UNSET) + + oauth_client_secret_unencrypted = d.pop("oauthClientSecretUnencrypted", UNSET) + + def _parse_offloaded_schemas(data: object) -> list[str] | str | Unset: + if isinstance(data, Unset): + return data + try: + if not isinstance(data, list): + raise TypeError() + offloaded_schemas_type_1 = cast(list[str], data) + + return offloaded_schemas_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(list[str] | str | Unset, data) + + offloaded_schemas = _parse_offloaded_schemas(d.pop("offloadedSchemas", UNSET)) + + port = d.pop("port", UNSET) + + private_key = d.pop("privateKey", UNSET) + + query_timeout_seconds = d.pop("queryTimeoutSeconds", UNSET) + + query_timezone = d.pop("queryTimezone", UNSET) + + region = d.pop("region", UNSET) + + scratch_schema = d.pop("scratchSchema", UNSET) + + system_timezone = d.pop("systemTimezone", UNSET) + + trust_server_certificate = d.pop("trustServerCertificate", UNSET) + + use_machine_auth = d.pop("useMachineAuth", UNSET) + + username = d.pop("username", UNSET) + + warehouse = d.pop("warehouse", UNSET) + + wif_audience = d.pop("wifAudience", UNSET) + + wif_service_account_email = d.pop("wifServiceAccountEmail", UNSET) + + connections_create_connections_create_body = cls( + dialect=dialect, + name=name, + password_unencrypted=password_unencrypted, + accepts_license=accepts_license, + allows_user_specific_timezones=allows_user_specific_timezones, + always_scope_view_names=always_scope_view_names, + authentication_type=authentication_type, + aws_role_arn=aws_role_arn, + base_role=base_role, + database=database, + default_schema=default_schema, + enable_db_semantic_layer_integration=enable_db_semantic_layer_integration, + enable_db_semantic_layer_topics=enable_db_semantic_layer_topics, + external_oauth_audience=external_oauth_audience, + external_oauth_authorization_url=external_oauth_authorization_url, + external_oauth_token_url=external_oauth_token_url, + host=host, + host_override=host_override, + include_other_catalogs=include_other_catalogs, + include_schemas=include_schemas, + infer_relationships_from_column_names=infer_relationships_from_column_names, + infer_relationships_from_foreign_keys=infer_relationships_from_foreign_keys, + max_billing_bytes=max_billing_bytes, + oauth_client_id=oauth_client_id, + oauth_client_secret_unencrypted=oauth_client_secret_unencrypted, + offloaded_schemas=offloaded_schemas, + port=port, + private_key=private_key, + query_timeout_seconds=query_timeout_seconds, + query_timezone=query_timezone, + region=region, + scratch_schema=scratch_schema, + system_timezone=system_timezone, + trust_server_certificate=trust_server_certificate, + use_machine_auth=use_machine_auth, + username=username, + warehouse=warehouse, + wif_audience=wif_audience, + wif_service_account_email=wif_service_account_email, + ) + + connections_create_connections_create_body.additional_properties = d + return connections_create_connections_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_create_connections_create_body_base_role.py b/omni_python_sdk/models/connections_create_connections_create_body_base_role.py new file mode 100644 index 0000000..3fa014e --- /dev/null +++ b/omni_python_sdk/models/connections_create_connections_create_body_base_role.py @@ -0,0 +1,24 @@ +from typing import Literal + +ConnectionsCreateConnectionsCreateBodyBaseRole = Literal[ + "CONNECTION_ADMIN", "MODELER", "NO_ACCESS", "QUERIER", "RESTRICTED_QUERIER", "VIEWER" +] + +CONNECTIONS_CREATE_CONNECTIONS_CREATE_BODY_BASE_ROLE_VALUES: set[ConnectionsCreateConnectionsCreateBodyBaseRole] = { + "CONNECTION_ADMIN", + "MODELER", + "NO_ACCESS", + "QUERIER", + "RESTRICTED_QUERIER", + "VIEWER", +} + + +def check_connections_create_connections_create_body_base_role( + value: str, +) -> ConnectionsCreateConnectionsCreateBodyBaseRole: + if value in CONNECTIONS_CREATE_CONNECTIONS_CREATE_BODY_BASE_ROLE_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CONNECTIONS_CREATE_CONNECTIONS_CREATE_BODY_BASE_ROLE_VALUES!r}" + ) diff --git a/omni_python_sdk/models/connections_create_connections_create_body_dialect.py b/omni_python_sdk/models/connections_create_connections_create_body_dialect.py new file mode 100644 index 0000000..a3a89d2 --- /dev/null +++ b/omni_python_sdk/models/connections_create_connections_create_body_dialect.py @@ -0,0 +1,51 @@ +from typing import Literal + +ConnectionsCreateConnectionsCreateBodyDialect = Literal[ + "athena", + "bigquery", + "clickhouse", + "databricks", + "databricks_lakebase", + "exasol", + "mariadb", + "motherduck", + "mssql", + "mysql", + "oracle", + "postgres", + "redshift", + "sap_hana", + "snowflake", + "starrocks", + "trino", +] + +CONNECTIONS_CREATE_CONNECTIONS_CREATE_BODY_DIALECT_VALUES: set[ConnectionsCreateConnectionsCreateBodyDialect] = { + "athena", + "bigquery", + "clickhouse", + "databricks", + "databricks_lakebase", + "exasol", + "mariadb", + "motherduck", + "mssql", + "mysql", + "oracle", + "postgres", + "redshift", + "sap_hana", + "snowflake", + "starrocks", + "trino", +} + + +def check_connections_create_connections_create_body_dialect( + value: str, +) -> ConnectionsCreateConnectionsCreateBodyDialect: + if value in CONNECTIONS_CREATE_CONNECTIONS_CREATE_BODY_DIALECT_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CONNECTIONS_CREATE_CONNECTIONS_CREATE_BODY_DIALECT_VALUES!r}" + ) diff --git a/omni_python_sdk/models/connections_create_connections_create_response.py b/omni_python_sdk/models/connections_create_connections_create_response.py new file mode 100644 index 0000000..ef8577e --- /dev/null +++ b/omni_python_sdk/models/connections_create_connections_create_response.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsCreateConnectionsCreateResponse") + + +@_attrs_define +class ConnectionsCreateConnectionsCreateResponse: + """Create connection response + + Attributes: + data (UUID): Created connection ID Example: 550e8400-e29b-41d4-a716-446655440000. + success (bool): Whether the operation succeeded Example: True. + """ + + data: UUID + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data = str(self.data) + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "data": data, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + data = UUID(d.pop("data")) + + success = d.pop("success") + + connections_create_connections_create_response = cls( + data=data, + success=success, + ) + + connections_create_connections_create_response.additional_properties = d + return connections_create_connections_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_dbt_delete_connections_dbt_delete_response.py b/omni_python_sdk/models/connections_dbt_delete_connections_dbt_delete_response.py new file mode 100644 index 0000000..351e70d --- /dev/null +++ b/omni_python_sdk/models/connections_dbt_delete_connections_dbt_delete_response.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsDbtDeleteConnectionsDbtDeleteResponse") + + +@_attrs_define +class ConnectionsDbtDeleteConnectionsDbtDeleteResponse: + """dbt delete response + + Attributes: + message (str): Success message Example: dbt repository unlinked successfully. + success (bool): Whether the operation succeeded Example: True. + """ + + message: str + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + success = d.pop("success") + + connections_dbt_delete_connections_dbt_delete_response = cls( + message=message, + success=success, + ) + + connections_dbt_delete_connections_dbt_delete_response.additional_properties = d + return connections_dbt_delete_connections_dbt_delete_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_dbt_environments_list_sort_direction.py b/omni_python_sdk/models/connections_dbt_environments_list_sort_direction.py new file mode 100644 index 0000000..12f1d51 --- /dev/null +++ b/omni_python_sdk/models/connections_dbt_environments_list_sort_direction.py @@ -0,0 +1,16 @@ +from typing import Literal + +ConnectionsDbtEnvironmentsListSortDirection = Literal["asc", "desc"] + +CONNECTIONS_DBT_ENVIRONMENTS_LIST_SORT_DIRECTION_VALUES: set[ConnectionsDbtEnvironmentsListSortDirection] = { + "asc", + "desc", +} + + +def check_connections_dbt_environments_list_sort_direction(value: str) -> ConnectionsDbtEnvironmentsListSortDirection: + if value in CONNECTIONS_DBT_ENVIRONMENTS_LIST_SORT_DIRECTION_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CONNECTIONS_DBT_ENVIRONMENTS_LIST_SORT_DIRECTION_VALUES!r}" + ) diff --git a/omni_python_sdk/models/connections_dbt_environments_list_sort_field.py b/omni_python_sdk/models/connections_dbt_environments_list_sort_field.py new file mode 100644 index 0000000..c6df8c0 --- /dev/null +++ b/omni_python_sdk/models/connections_dbt_environments_list_sort_field.py @@ -0,0 +1,15 @@ +from typing import Literal + +ConnectionsDbtEnvironmentsListSortField = Literal["name"] + +CONNECTIONS_DBT_ENVIRONMENTS_LIST_SORT_FIELD_VALUES: set[ConnectionsDbtEnvironmentsListSortField] = { + "name", +} + + +def check_connections_dbt_environments_list_sort_field(value: str) -> ConnectionsDbtEnvironmentsListSortField: + if value in CONNECTIONS_DBT_ENVIRONMENTS_LIST_SORT_FIELD_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CONNECTIONS_DBT_ENVIRONMENTS_LIST_SORT_FIELD_VALUES!r}" + ) diff --git a/omni_python_sdk/models/connections_dbt_get_dbt_configured_response.py b/omni_python_sdk/models/connections_dbt_get_dbt_configured_response.py new file mode 100644 index 0000000..6950e19 --- /dev/null +++ b/omni_python_sdk/models/connections_dbt_get_dbt_configured_response.py @@ -0,0 +1,124 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsDbtGetDbtConfiguredResponse") + + +@_attrs_define +class ConnectionsDbtGetDbtConfiguredResponse: + """dbt repository configuration response + + Attributes: + autogen_relationships (bool): Whether relationships are auto-generated from dbt Example: True. + branch (str): Git branch name Example: main. + dbt_version (str): dbt version being used Example: Auto. + enable_semantic_layer (bool): Whether the dbt semantic layer integration is enabled + enable_virtual_schemas (bool): Whether virtual schemas are enabled + project_root_path (None | str): Path to dbt project root Example: dbt_project. + ssh_url (str): SSH URL for git repository Example: git@github.com:org/repo.git. + supports_dbt (bool): Indicates dbt is supported and configured Example: True. + """ + + autogen_relationships: bool + branch: str + dbt_version: str + enable_semantic_layer: bool + enable_virtual_schemas: bool + project_root_path: None | str + ssh_url: str + supports_dbt: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + autogen_relationships = self.autogen_relationships + + branch = self.branch + + dbt_version = self.dbt_version + + enable_semantic_layer = self.enable_semantic_layer + + enable_virtual_schemas = self.enable_virtual_schemas + + project_root_path: None | str + project_root_path = self.project_root_path + + ssh_url = self.ssh_url + + supports_dbt = self.supports_dbt + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "autogenRelationships": autogen_relationships, + "branch": branch, + "dbtVersion": dbt_version, + "enableSemanticLayer": enable_semantic_layer, + "enableVirtualSchemas": enable_virtual_schemas, + "projectRootPath": project_root_path, + "sshUrl": ssh_url, + "supportsDbt": supports_dbt, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + autogen_relationships = d.pop("autogenRelationships") + + branch = d.pop("branch") + + dbt_version = d.pop("dbtVersion") + + enable_semantic_layer = d.pop("enableSemanticLayer") + + enable_virtual_schemas = d.pop("enableVirtualSchemas") + + def _parse_project_root_path(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + project_root_path = _parse_project_root_path(d.pop("projectRootPath")) + + ssh_url = d.pop("sshUrl") + + supports_dbt = d.pop("supportsDbt") + + connections_dbt_get_dbt_configured_response = cls( + autogen_relationships=autogen_relationships, + branch=branch, + dbt_version=dbt_version, + enable_semantic_layer=enable_semantic_layer, + enable_virtual_schemas=enable_virtual_schemas, + project_root_path=project_root_path, + ssh_url=ssh_url, + supports_dbt=supports_dbt, + ) + + connections_dbt_get_dbt_configured_response.additional_properties = d + return connections_dbt_get_dbt_configured_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_dbt_get_dbt_not_configured_response.py b/omni_python_sdk/models/connections_dbt_get_dbt_not_configured_response.py new file mode 100644 index 0000000..8de6bdc --- /dev/null +++ b/omni_python_sdk/models/connections_dbt_get_dbt_not_configured_response.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsDbtGetDbtNotConfiguredResponse") + + +@_attrs_define +class ConnectionsDbtGetDbtNotConfiguredResponse: + """Response when dbt is not configured + + Attributes: + message (str): Message explaining dbt status Example: dbt not configured for this connection. + supports_dbt (bool): Whether the connection dialect supports dbt Example: True. + """ + + message: str + supports_dbt: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + supports_dbt = self.supports_dbt + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + "supportsDbt": supports_dbt, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + supports_dbt = d.pop("supportsDbt") + + connections_dbt_get_dbt_not_configured_response = cls( + message=message, + supports_dbt=supports_dbt, + ) + + connections_dbt_get_dbt_not_configured_response.additional_properties = d + return connections_dbt_get_dbt_not_configured_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_dbt_update_connections_dbt_update_body.py b/omni_python_sdk/models/connections_dbt_update_connections_dbt_update_body.py new file mode 100644 index 0000000..6d0ebba --- /dev/null +++ b/omni_python_sdk/models/connections_dbt_update_connections_dbt_update_body.py @@ -0,0 +1,165 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.connections_dbt_update_connections_dbt_update_body_project_root_path_type_1 import ( + ConnectionsDbtUpdateConnectionsDbtUpdateBodyProjectRootPathType1, + check_connections_dbt_update_connections_dbt_update_body_project_root_path_type_1, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ConnectionsDbtUpdateConnectionsDbtUpdateBody") + + +@_attrs_define +class ConnectionsDbtUpdateConnectionsDbtUpdateBody: + """dbt repository configuration + + Attributes: + autogen_relationships (bool): Automatically generate relationships from dbt Example: True. + branch (str): Git branch name Example: main. + enable_virtual_schemas (bool): Enable virtual schemas from dbt + ssh_url (str): SSH URL for git repository Example: git@github.com:org/repo.git. + dbt_version (None | str | Unset): dbt version to use. Supported: Auto, 1.11, 1.12 Example: 1.11. + enable_semantic_layer (bool | Unset): Enable dbt semantic layer integration Default: False. + project_root_path (ConnectionsDbtUpdateConnectionsDbtUpdateBodyProjectRootPathType1 | None | str | Unset): Path + to dbt project root within repository Example: dbt_project. + rotate_keys (bool | Unset): Rotate SSH deploy keys Default: False. + """ + + autogen_relationships: bool + branch: str + enable_virtual_schemas: bool + ssh_url: str + dbt_version: None | str | Unset = UNSET + enable_semantic_layer: bool | Unset = False + project_root_path: ConnectionsDbtUpdateConnectionsDbtUpdateBodyProjectRootPathType1 | None | str | Unset = UNSET + rotate_keys: bool | Unset = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + autogen_relationships = self.autogen_relationships + + branch = self.branch + + enable_virtual_schemas = self.enable_virtual_schemas + + ssh_url = self.ssh_url + + dbt_version: None | str | Unset + if isinstance(self.dbt_version, Unset): + dbt_version = UNSET + else: + dbt_version = self.dbt_version + + enable_semantic_layer = self.enable_semantic_layer + + project_root_path: None | str | Unset + if isinstance(self.project_root_path, Unset): + project_root_path = UNSET + elif isinstance(self.project_root_path, str): + project_root_path = self.project_root_path + else: + project_root_path = self.project_root_path + + rotate_keys = self.rotate_keys + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "autogenRelationships": autogen_relationships, + "branch": branch, + "enableVirtualSchemas": enable_virtual_schemas, + "sshUrl": ssh_url, + } + ) + if dbt_version is not UNSET: + field_dict["dbtVersion"] = dbt_version + if enable_semantic_layer is not UNSET: + field_dict["enableSemanticLayer"] = enable_semantic_layer + if project_root_path is not UNSET: + field_dict["projectRootPath"] = project_root_path + if rotate_keys is not UNSET: + field_dict["rotateKeys"] = rotate_keys + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + autogen_relationships = d.pop("autogenRelationships") + + branch = d.pop("branch") + + enable_virtual_schemas = d.pop("enableVirtualSchemas") + + ssh_url = d.pop("sshUrl") + + def _parse_dbt_version(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + dbt_version = _parse_dbt_version(d.pop("dbtVersion", UNSET)) + + enable_semantic_layer = d.pop("enableSemanticLayer", UNSET) + + def _parse_project_root_path( + data: object, + ) -> ConnectionsDbtUpdateConnectionsDbtUpdateBodyProjectRootPathType1 | None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + project_root_path_type_1 = ( + check_connections_dbt_update_connections_dbt_update_body_project_root_path_type_1(data) + ) + + return project_root_path_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(ConnectionsDbtUpdateConnectionsDbtUpdateBodyProjectRootPathType1 | None | str | Unset, data) + + project_root_path = _parse_project_root_path(d.pop("projectRootPath", UNSET)) + + rotate_keys = d.pop("rotateKeys", UNSET) + + connections_dbt_update_connections_dbt_update_body = cls( + autogen_relationships=autogen_relationships, + branch=branch, + enable_virtual_schemas=enable_virtual_schemas, + ssh_url=ssh_url, + dbt_version=dbt_version, + enable_semantic_layer=enable_semantic_layer, + project_root_path=project_root_path, + rotate_keys=rotate_keys, + ) + + connections_dbt_update_connections_dbt_update_body.additional_properties = d + return connections_dbt_update_connections_dbt_update_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_dbt_update_connections_dbt_update_body_project_root_path_type_1.py b/omni_python_sdk/models/connections_dbt_update_connections_dbt_update_body_project_root_path_type_1.py new file mode 100644 index 0000000..ac19c73 --- /dev/null +++ b/omni_python_sdk/models/connections_dbt_update_connections_dbt_update_body_project_root_path_type_1.py @@ -0,0 +1,19 @@ +from typing import Literal + +ConnectionsDbtUpdateConnectionsDbtUpdateBodyProjectRootPathType1 = Literal[""] + +CONNECTIONS_DBT_UPDATE_CONNECTIONS_DBT_UPDATE_BODY_PROJECT_ROOT_PATH_TYPE_1_VALUES: set[ + ConnectionsDbtUpdateConnectionsDbtUpdateBodyProjectRootPathType1 +] = { + "", +} + + +def check_connections_dbt_update_connections_dbt_update_body_project_root_path_type_1( + value: str, +) -> ConnectionsDbtUpdateConnectionsDbtUpdateBodyProjectRootPathType1: + if value in CONNECTIONS_DBT_UPDATE_CONNECTIONS_DBT_UPDATE_BODY_PROJECT_ROOT_PATH_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CONNECTIONS_DBT_UPDATE_CONNECTIONS_DBT_UPDATE_BODY_PROJECT_ROOT_PATH_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/connections_dbt_update_connections_dbt_update_response.py b/omni_python_sdk/models/connections_dbt_update_connections_dbt_update_response.py new file mode 100644 index 0000000..a77b2e7 --- /dev/null +++ b/omni_python_sdk/models/connections_dbt_update_connections_dbt_update_response.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsDbtUpdateConnectionsDbtUpdateResponse") + + +@_attrs_define +class ConnectionsDbtUpdateConnectionsDbtUpdateResponse: + """dbt update response + + Attributes: + message (str): Success message Example: dbt configuration updated successfully. + success (bool): Whether the operation succeeded Example: True. + """ + + message: str + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + success = d.pop("success") + + connections_dbt_update_connections_dbt_update_response = cls( + message=message, + success=success, + ) + + connections_dbt_update_connections_dbt_update_response.additional_properties = d + return connections_dbt_update_connections_dbt_update_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_delete_connections_delete_response.py b/omni_python_sdk/models/connections_delete_connections_delete_response.py new file mode 100644 index 0000000..85577ec --- /dev/null +++ b/omni_python_sdk/models/connections_delete_connections_delete_response.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsDeleteConnectionsDeleteResponse") + + +@_attrs_define +class ConnectionsDeleteConnectionsDeleteResponse: + """Archive connection response + + Attributes: + message (str): Status message describing the result Example: Connection moved to trash.. + success (bool): True when the connection was archived Example: True. + """ + + message: str + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + success = d.pop("success") + + connections_delete_connections_delete_response = cls( + message=message, + success=success, + ) + + connections_delete_connections_delete_response.additional_properties = d + return connections_delete_connections_delete_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_get_connections_get_response.py b/omni_python_sdk/models/connections_get_connections_get_response.py new file mode 100644 index 0000000..6a39262 --- /dev/null +++ b/omni_python_sdk/models/connections_get_connections_get_response.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.connections_get_connections_get_response_connection import ( + ConnectionsGetConnectionsGetResponseConnection, + ) + + +T = TypeVar("T", bound="ConnectionsGetConnectionsGetResponse") + + +@_attrs_define +class ConnectionsGetConnectionsGetResponse: + """Get connection response + + Attributes: + connection (ConnectionsGetConnectionsGetResponseConnection): Connection object + """ + + connection: ConnectionsGetConnectionsGetResponseConnection + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + connection = self.connection.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "connection": connection, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.connections_get_connections_get_response_connection import ( + ConnectionsGetConnectionsGetResponseConnection, + ) + + d = dict(src_dict) + connection = ConnectionsGetConnectionsGetResponseConnection.from_dict(d.pop("connection")) + + connections_get_connections_get_response = cls( + connection=connection, + ) + + connections_get_connections_get_response.additional_properties = d + return connections_get_connections_get_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_get_connections_get_response_connection.py b/omni_python_sdk/models/connections_get_connections_get_response_connection.py new file mode 100644 index 0000000..ba19ab1 --- /dev/null +++ b/omni_python_sdk/models/connections_get_connections_get_response_connection.py @@ -0,0 +1,253 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.connections_get_connections_get_response_connection_dialect import ( + ConnectionsGetConnectionsGetResponseConnectionDialect, + check_connections_get_connections_get_response_connection_dialect, +) + +T = TypeVar("T", bound="ConnectionsGetConnectionsGetResponseConnection") + + +@_attrs_define +class ConnectionsGetConnectionsGetResponseConnection: + """Connection object + + Attributes: + allow_branch_connection_environments (bool | None): Whether a branch may select its own connection environment. + When user-attribute environment selection is also enabled, a branch selection overrides the user attribute. + base_role (None | str): Default role for users on this connection Example: QUERIER. + branch_connection_environment_overrides_user_attr (bool | None): Deprecated alias for + `allowBranchConnectionEnvironments`; same value. Use `allowBranchConnectionEnvironments` instead. + created_at (str): Timestamp when connection was created (ISO 8601) Example: 2024-01-15T10:30:00Z. + database (None | str): Database name Example: analytics_db. + default_schema (None | str): Default schema for the connection Example: public. + deleted_at (None | str): Timestamp when connection was deleted (ISO 8601) + dialect (ConnectionsGetConnectionsGetResponseConnectionDialect): Database dialect type Example: snowflake. + environment_connection_switches_schema_model (bool | None): Whether environment connections switch schema model + id (UUID): Unique connection identifier Example: 550e8400-e29b-41d4-a716-446655440000. + name (str): Connection display name Example: Production Snowflake. + updated_at (str): Timestamp when connection was last updated (ISO 8601) Example: 2024-01-15T10:30:00Z. + user_attribute_name_for_connection_environments (None | str): User attribute name used for connection + environments Example: region. + user_attribute_values_for_default_environment (list[str] | None): Default user attribute values for the base + environment Example: ['us-east', 'us-west']. + """ + + allow_branch_connection_environments: bool | None + base_role: None | str + branch_connection_environment_overrides_user_attr: bool | None + created_at: str + database: None | str + default_schema: None | str + deleted_at: None | str + dialect: ConnectionsGetConnectionsGetResponseConnectionDialect + environment_connection_switches_schema_model: bool | None + id: UUID + name: str + updated_at: str + user_attribute_name_for_connection_environments: None | str + user_attribute_values_for_default_environment: list[str] | None + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + allow_branch_connection_environments: bool | None + allow_branch_connection_environments = self.allow_branch_connection_environments + + base_role: None | str + base_role = self.base_role + + branch_connection_environment_overrides_user_attr: bool | None + branch_connection_environment_overrides_user_attr = self.branch_connection_environment_overrides_user_attr + + created_at = self.created_at + + database: None | str + database = self.database + + default_schema: None | str + default_schema = self.default_schema + + deleted_at: None | str + deleted_at = self.deleted_at + + dialect: str = self.dialect + + environment_connection_switches_schema_model: bool | None + environment_connection_switches_schema_model = self.environment_connection_switches_schema_model + + id = str(self.id) + + name = self.name + + updated_at = self.updated_at + + user_attribute_name_for_connection_environments: None | str + user_attribute_name_for_connection_environments = self.user_attribute_name_for_connection_environments + + user_attribute_values_for_default_environment: list[str] | None + if isinstance(self.user_attribute_values_for_default_environment, list): + user_attribute_values_for_default_environment = self.user_attribute_values_for_default_environment + + else: + user_attribute_values_for_default_environment = self.user_attribute_values_for_default_environment + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "allowBranchConnectionEnvironments": allow_branch_connection_environments, + "baseRole": base_role, + "branchConnectionEnvironmentOverridesUserAttr": branch_connection_environment_overrides_user_attr, + "createdAt": created_at, + "database": database, + "defaultSchema": default_schema, + "deletedAt": deleted_at, + "dialect": dialect, + "environmentConnectionSwitchesSchemaModel": environment_connection_switches_schema_model, + "id": id, + "name": name, + "updatedAt": updated_at, + "userAttributeNameForConnectionEnvironments": user_attribute_name_for_connection_environments, + "userAttributeValuesForDefaultEnvironment": user_attribute_values_for_default_environment, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_allow_branch_connection_environments(data: object) -> bool | None: + if data is None: + return data + return cast(bool | None, data) + + allow_branch_connection_environments = _parse_allow_branch_connection_environments( + d.pop("allowBranchConnectionEnvironments") + ) + + def _parse_base_role(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + base_role = _parse_base_role(d.pop("baseRole")) + + def _parse_branch_connection_environment_overrides_user_attr(data: object) -> bool | None: + if data is None: + return data + return cast(bool | None, data) + + branch_connection_environment_overrides_user_attr = _parse_branch_connection_environment_overrides_user_attr( + d.pop("branchConnectionEnvironmentOverridesUserAttr") + ) + + created_at = d.pop("createdAt") + + def _parse_database(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + database = _parse_database(d.pop("database")) + + def _parse_default_schema(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + default_schema = _parse_default_schema(d.pop("defaultSchema")) + + def _parse_deleted_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + deleted_at = _parse_deleted_at(d.pop("deletedAt")) + + dialect = check_connections_get_connections_get_response_connection_dialect(d.pop("dialect")) + + def _parse_environment_connection_switches_schema_model(data: object) -> bool | None: + if data is None: + return data + return cast(bool | None, data) + + environment_connection_switches_schema_model = _parse_environment_connection_switches_schema_model( + d.pop("environmentConnectionSwitchesSchemaModel") + ) + + id = UUID(d.pop("id")) + + name = d.pop("name") + + updated_at = d.pop("updatedAt") + + def _parse_user_attribute_name_for_connection_environments(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + user_attribute_name_for_connection_environments = _parse_user_attribute_name_for_connection_environments( + d.pop("userAttributeNameForConnectionEnvironments") + ) + + def _parse_user_attribute_values_for_default_environment(data: object) -> list[str] | None: + if data is None: + return data + try: + if not isinstance(data, list): + raise TypeError() + user_attribute_values_for_default_environment_type_0 = cast(list[str], data) + + return user_attribute_values_for_default_environment_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(list[str] | None, data) + + user_attribute_values_for_default_environment = _parse_user_attribute_values_for_default_environment( + d.pop("userAttributeValuesForDefaultEnvironment") + ) + + connections_get_connections_get_response_connection = cls( + allow_branch_connection_environments=allow_branch_connection_environments, + base_role=base_role, + branch_connection_environment_overrides_user_attr=branch_connection_environment_overrides_user_attr, + created_at=created_at, + database=database, + default_schema=default_schema, + deleted_at=deleted_at, + dialect=dialect, + environment_connection_switches_schema_model=environment_connection_switches_schema_model, + id=id, + name=name, + updated_at=updated_at, + user_attribute_name_for_connection_environments=user_attribute_name_for_connection_environments, + user_attribute_values_for_default_environment=user_attribute_values_for_default_environment, + ) + + connections_get_connections_get_response_connection.additional_properties = d + return connections_get_connections_get_response_connection + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_get_connections_get_response_connection_dialect.py b/omni_python_sdk/models/connections_get_connections_get_response_connection_dialect.py new file mode 100644 index 0000000..835d458 --- /dev/null +++ b/omni_python_sdk/models/connections_get_connections_get_response_connection_dialect.py @@ -0,0 +1,49 @@ +from typing import Literal + +ConnectionsGetConnectionsGetResponseConnectionDialect = Literal[ + "athena", + "bigquery", + "clickhouse", + "databricks", + "databricks_lakebase", + "duckdb", + "mariadb", + "motherduck", + "mysql", + "postgres", + "redshift", + "singlestore", + "snowflake", + "sqlserver", + "trino", +] + +CONNECTIONS_GET_CONNECTIONS_GET_RESPONSE_CONNECTION_DIALECT_VALUES: set[ + ConnectionsGetConnectionsGetResponseConnectionDialect +] = { + "athena", + "bigquery", + "clickhouse", + "databricks", + "databricks_lakebase", + "duckdb", + "mariadb", + "motherduck", + "mysql", + "postgres", + "redshift", + "singlestore", + "snowflake", + "sqlserver", + "trino", +} + + +def check_connections_get_connections_get_response_connection_dialect( + value: str, +) -> ConnectionsGetConnectionsGetResponseConnectionDialect: + if value in CONNECTIONS_GET_CONNECTIONS_GET_RESPONSE_CONNECTION_DIALECT_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CONNECTIONS_GET_CONNECTIONS_GET_RESPONSE_CONNECTION_DIALECT_VALUES!r}" + ) diff --git a/omni_python_sdk/models/connections_list_connections_list_response.py b/omni_python_sdk/models/connections_list_connections_list_response.py new file mode 100644 index 0000000..c38af66 --- /dev/null +++ b/omni_python_sdk/models/connections_list_connections_list_response.py @@ -0,0 +1,80 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.connections_list_connections_list_response_connection import ( + ConnectionsListConnectionsListResponseConnection, + ) + + +T = TypeVar("T", bound="ConnectionsListConnectionsListResponse") + + +@_attrs_define +class ConnectionsListConnectionsListResponse: + """List connections response + + Attributes: + connections (list[ConnectionsListConnectionsListResponseConnection]): List of connections + """ + + connections: list[ConnectionsListConnectionsListResponseConnection] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + connections = [] + for connections_item_data in self.connections: + connections_item = connections_item_data.to_dict() + connections.append(connections_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "connections": connections, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.connections_list_connections_list_response_connection import ( + ConnectionsListConnectionsListResponseConnection, + ) + + d = dict(src_dict) + connections = [] + _connections = d.pop("connections") + for connections_item_data in _connections: + connections_item = ConnectionsListConnectionsListResponseConnection.from_dict(connections_item_data) + + connections.append(connections_item) + + connections_list_connections_list_response = cls( + connections=connections, + ) + + connections_list_connections_list_response.additional_properties = d + return connections_list_connections_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_list_connections_list_response_connection.py b/omni_python_sdk/models/connections_list_connections_list_response_connection.py new file mode 100644 index 0000000..2d78e94 --- /dev/null +++ b/omni_python_sdk/models/connections_list_connections_list_response_connection.py @@ -0,0 +1,253 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.connections_list_connections_list_response_connection_dialect import ( + ConnectionsListConnectionsListResponseConnectionDialect, + check_connections_list_connections_list_response_connection_dialect, +) + +T = TypeVar("T", bound="ConnectionsListConnectionsListResponseConnection") + + +@_attrs_define +class ConnectionsListConnectionsListResponseConnection: + """Connection object + + Attributes: + allow_branch_connection_environments (bool | None): Whether a branch may select its own connection environment. + When user-attribute environment selection is also enabled, a branch selection overrides the user attribute. + base_role (None | str): Default role for users on this connection Example: QUERIER. + branch_connection_environment_overrides_user_attr (bool | None): Deprecated alias for + `allowBranchConnectionEnvironments`; same value. Use `allowBranchConnectionEnvironments` instead. + created_at (str): Timestamp when connection was created (ISO 8601) Example: 2024-01-15T10:30:00Z. + database (None | str): Database name Example: analytics_db. + default_schema (None | str): Default schema for the connection Example: public. + deleted_at (None | str): Timestamp when connection was deleted (ISO 8601) + dialect (ConnectionsListConnectionsListResponseConnectionDialect): Database dialect type Example: snowflake. + environment_connection_switches_schema_model (bool | None): Whether environment connections switch schema model + id (UUID): Unique connection identifier Example: 550e8400-e29b-41d4-a716-446655440000. + name (str): Connection display name Example: Production Snowflake. + updated_at (str): Timestamp when connection was last updated (ISO 8601) Example: 2024-01-15T10:30:00Z. + user_attribute_name_for_connection_environments (None | str): User attribute name used for connection + environments Example: region. + user_attribute_values_for_default_environment (list[str] | None): Default user attribute values for the base + environment Example: ['us-east', 'us-west']. + """ + + allow_branch_connection_environments: bool | None + base_role: None | str + branch_connection_environment_overrides_user_attr: bool | None + created_at: str + database: None | str + default_schema: None | str + deleted_at: None | str + dialect: ConnectionsListConnectionsListResponseConnectionDialect + environment_connection_switches_schema_model: bool | None + id: UUID + name: str + updated_at: str + user_attribute_name_for_connection_environments: None | str + user_attribute_values_for_default_environment: list[str] | None + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + allow_branch_connection_environments: bool | None + allow_branch_connection_environments = self.allow_branch_connection_environments + + base_role: None | str + base_role = self.base_role + + branch_connection_environment_overrides_user_attr: bool | None + branch_connection_environment_overrides_user_attr = self.branch_connection_environment_overrides_user_attr + + created_at = self.created_at + + database: None | str + database = self.database + + default_schema: None | str + default_schema = self.default_schema + + deleted_at: None | str + deleted_at = self.deleted_at + + dialect: str = self.dialect + + environment_connection_switches_schema_model: bool | None + environment_connection_switches_schema_model = self.environment_connection_switches_schema_model + + id = str(self.id) + + name = self.name + + updated_at = self.updated_at + + user_attribute_name_for_connection_environments: None | str + user_attribute_name_for_connection_environments = self.user_attribute_name_for_connection_environments + + user_attribute_values_for_default_environment: list[str] | None + if isinstance(self.user_attribute_values_for_default_environment, list): + user_attribute_values_for_default_environment = self.user_attribute_values_for_default_environment + + else: + user_attribute_values_for_default_environment = self.user_attribute_values_for_default_environment + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "allowBranchConnectionEnvironments": allow_branch_connection_environments, + "baseRole": base_role, + "branchConnectionEnvironmentOverridesUserAttr": branch_connection_environment_overrides_user_attr, + "createdAt": created_at, + "database": database, + "defaultSchema": default_schema, + "deletedAt": deleted_at, + "dialect": dialect, + "environmentConnectionSwitchesSchemaModel": environment_connection_switches_schema_model, + "id": id, + "name": name, + "updatedAt": updated_at, + "userAttributeNameForConnectionEnvironments": user_attribute_name_for_connection_environments, + "userAttributeValuesForDefaultEnvironment": user_attribute_values_for_default_environment, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_allow_branch_connection_environments(data: object) -> bool | None: + if data is None: + return data + return cast(bool | None, data) + + allow_branch_connection_environments = _parse_allow_branch_connection_environments( + d.pop("allowBranchConnectionEnvironments") + ) + + def _parse_base_role(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + base_role = _parse_base_role(d.pop("baseRole")) + + def _parse_branch_connection_environment_overrides_user_attr(data: object) -> bool | None: + if data is None: + return data + return cast(bool | None, data) + + branch_connection_environment_overrides_user_attr = _parse_branch_connection_environment_overrides_user_attr( + d.pop("branchConnectionEnvironmentOverridesUserAttr") + ) + + created_at = d.pop("createdAt") + + def _parse_database(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + database = _parse_database(d.pop("database")) + + def _parse_default_schema(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + default_schema = _parse_default_schema(d.pop("defaultSchema")) + + def _parse_deleted_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + deleted_at = _parse_deleted_at(d.pop("deletedAt")) + + dialect = check_connections_list_connections_list_response_connection_dialect(d.pop("dialect")) + + def _parse_environment_connection_switches_schema_model(data: object) -> bool | None: + if data is None: + return data + return cast(bool | None, data) + + environment_connection_switches_schema_model = _parse_environment_connection_switches_schema_model( + d.pop("environmentConnectionSwitchesSchemaModel") + ) + + id = UUID(d.pop("id")) + + name = d.pop("name") + + updated_at = d.pop("updatedAt") + + def _parse_user_attribute_name_for_connection_environments(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + user_attribute_name_for_connection_environments = _parse_user_attribute_name_for_connection_environments( + d.pop("userAttributeNameForConnectionEnvironments") + ) + + def _parse_user_attribute_values_for_default_environment(data: object) -> list[str] | None: + if data is None: + return data + try: + if not isinstance(data, list): + raise TypeError() + user_attribute_values_for_default_environment_type_0 = cast(list[str], data) + + return user_attribute_values_for_default_environment_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(list[str] | None, data) + + user_attribute_values_for_default_environment = _parse_user_attribute_values_for_default_environment( + d.pop("userAttributeValuesForDefaultEnvironment") + ) + + connections_list_connections_list_response_connection = cls( + allow_branch_connection_environments=allow_branch_connection_environments, + base_role=base_role, + branch_connection_environment_overrides_user_attr=branch_connection_environment_overrides_user_attr, + created_at=created_at, + database=database, + default_schema=default_schema, + deleted_at=deleted_at, + dialect=dialect, + environment_connection_switches_schema_model=environment_connection_switches_schema_model, + id=id, + name=name, + updated_at=updated_at, + user_attribute_name_for_connection_environments=user_attribute_name_for_connection_environments, + user_attribute_values_for_default_environment=user_attribute_values_for_default_environment, + ) + + connections_list_connections_list_response_connection.additional_properties = d + return connections_list_connections_list_response_connection + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_list_connections_list_response_connection_dialect.py b/omni_python_sdk/models/connections_list_connections_list_response_connection_dialect.py new file mode 100644 index 0000000..00acab8 --- /dev/null +++ b/omni_python_sdk/models/connections_list_connections_list_response_connection_dialect.py @@ -0,0 +1,49 @@ +from typing import Literal + +ConnectionsListConnectionsListResponseConnectionDialect = Literal[ + "athena", + "bigquery", + "clickhouse", + "databricks", + "databricks_lakebase", + "duckdb", + "mariadb", + "motherduck", + "mysql", + "postgres", + "redshift", + "singlestore", + "snowflake", + "sqlserver", + "trino", +] + +CONNECTIONS_LIST_CONNECTIONS_LIST_RESPONSE_CONNECTION_DIALECT_VALUES: set[ + ConnectionsListConnectionsListResponseConnectionDialect +] = { + "athena", + "bigquery", + "clickhouse", + "databricks", + "databricks_lakebase", + "duckdb", + "mariadb", + "motherduck", + "mysql", + "postgres", + "redshift", + "singlestore", + "snowflake", + "sqlserver", + "trino", +} + + +def check_connections_list_connections_list_response_connection_dialect( + value: str, +) -> ConnectionsListConnectionsListResponseConnectionDialect: + if value in CONNECTIONS_LIST_CONNECTIONS_LIST_RESPONSE_CONNECTION_DIALECT_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CONNECTIONS_LIST_CONNECTIONS_LIST_RESPONSE_CONNECTION_DIALECT_VALUES!r}" + ) diff --git a/omni_python_sdk/models/connections_list_sort_direction.py b/omni_python_sdk/models/connections_list_sort_direction.py new file mode 100644 index 0000000..a7a92fe --- /dev/null +++ b/omni_python_sdk/models/connections_list_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +ConnectionsListSortDirection = Literal["asc", "desc"] + +CONNECTIONS_LIST_SORT_DIRECTION_VALUES: set[ConnectionsListSortDirection] = { + "asc", + "desc", +} + + +def check_connections_list_sort_direction(value: str) -> ConnectionsListSortDirection: + if value in CONNECTIONS_LIST_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {CONNECTIONS_LIST_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/connections_list_sort_field.py b/omni_python_sdk/models/connections_list_sort_field.py new file mode 100644 index 0000000..a2a0044 --- /dev/null +++ b/omni_python_sdk/models/connections_list_sort_field.py @@ -0,0 +1,15 @@ +from typing import Literal + +ConnectionsListSortField = Literal["database", "dialect", "name"] + +CONNECTIONS_LIST_SORT_FIELD_VALUES: set[ConnectionsListSortField] = { + "database", + "dialect", + "name", +} + + +def check_connections_list_sort_field(value: str) -> ConnectionsListSortField: + if value in CONNECTIONS_LIST_SORT_FIELD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {CONNECTIONS_LIST_SORT_FIELD_VALUES!r}") diff --git a/omni_python_sdk/models/connections_schedules_create_connections_schedules_create_body.py b/omni_python_sdk/models/connections_schedules_create_connections_schedules_create_body.py new file mode 100644 index 0000000..9b80095 --- /dev/null +++ b/omni_python_sdk/models/connections_schedules_create_connections_schedules_create_body.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ConnectionsSchedulesCreateConnectionsSchedulesCreateBody") + + +@_attrs_define +class ConnectionsSchedulesCreateConnectionsSchedulesCreateBody: + """Request body for creating a schema refresh schedule + + Attributes: + schedule (str): AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See + https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html Example: 0 2 * * ? *. + timezone (str): IANA timezone for schedule execution Example: America/New_York. + hard_refresh (bool | Unset): When true, the scheduled refresh performs a hard refresh that fully discards and + rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated + views with the existing model. Default: False. + """ + + schedule: str + timezone: str + hard_refresh: bool | Unset = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + schedule = self.schedule + + timezone = self.timezone + + hard_refresh = self.hard_refresh + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "schedule": schedule, + "timezone": timezone, + } + ) + if hard_refresh is not UNSET: + field_dict["hardRefresh"] = hard_refresh + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + schedule = d.pop("schedule") + + timezone = d.pop("timezone") + + hard_refresh = d.pop("hardRefresh", UNSET) + + connections_schedules_create_connections_schedules_create_body = cls( + schedule=schedule, + timezone=timezone, + hard_refresh=hard_refresh, + ) + + connections_schedules_create_connections_schedules_create_body.additional_properties = d + return connections_schedules_create_connections_schedules_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_schedules_create_connections_schedules_create_response.py b/omni_python_sdk/models/connections_schedules_create_connections_schedules_create_response.py new file mode 100644 index 0000000..1720f56 --- /dev/null +++ b/omni_python_sdk/models/connections_schedules_create_connections_schedules_create_response.py @@ -0,0 +1,136 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse") + + +@_attrs_define +class ConnectionsSchedulesCreateConnectionsSchedulesCreateResponse: + """Created schedule response + + Attributes: + connection_id (UUID): Connection ID this schedule belongs to Example: 550e8400-e29b-41d4-a716-446655440000. + created_at (str): Schedule creation timestamp (ISO 8601) Example: 2024-01-15T10:30:00Z. + description (str): Human-readable schedule description Example: Runs daily at 2:00 AM EST. + disabled_at (None | str): Timestamp when schedule was disabled (ISO 8601) + hard_refresh (bool): When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds + the schema model. When false, it performs a soft refresh that merges newly generated views with the existing + model. + schedule (str): AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See + https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html Example: 0 2 * * ? *. + schedule_id (UUID): Unique schedule identifier Example: 550e8400-e29b-41d4-a716-446655440001. + timezone (str): IANA timezone for schedule execution Example: America/New_York. + updated_at (str): Schedule last update timestamp (ISO 8601) Example: 2024-01-15T10:30:00Z. + """ + + connection_id: UUID + created_at: str + description: str + disabled_at: None | str + hard_refresh: bool + schedule: str + schedule_id: UUID + timezone: str + updated_at: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + connection_id = str(self.connection_id) + + created_at = self.created_at + + description = self.description + + disabled_at: None | str + disabled_at = self.disabled_at + + hard_refresh = self.hard_refresh + + schedule = self.schedule + + schedule_id = str(self.schedule_id) + + timezone = self.timezone + + updated_at = self.updated_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "connectionId": connection_id, + "createdAt": created_at, + "description": description, + "disabledAt": disabled_at, + "hardRefresh": hard_refresh, + "schedule": schedule, + "scheduleId": schedule_id, + "timezone": timezone, + "updatedAt": updated_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + connection_id = UUID(d.pop("connectionId")) + + created_at = d.pop("createdAt") + + description = d.pop("description") + + def _parse_disabled_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + disabled_at = _parse_disabled_at(d.pop("disabledAt")) + + hard_refresh = d.pop("hardRefresh") + + schedule = d.pop("schedule") + + schedule_id = UUID(d.pop("scheduleId")) + + timezone = d.pop("timezone") + + updated_at = d.pop("updatedAt") + + connections_schedules_create_connections_schedules_create_response = cls( + connection_id=connection_id, + created_at=created_at, + description=description, + disabled_at=disabled_at, + hard_refresh=hard_refresh, + schedule=schedule, + schedule_id=schedule_id, + timezone=timezone, + updated_at=updated_at, + ) + + connections_schedules_create_connections_schedules_create_response.additional_properties = d + return connections_schedules_create_connections_schedules_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_schedules_delete_connections_schedules_delete_response.py b/omni_python_sdk/models/connections_schedules_delete_connections_schedules_delete_response.py new file mode 100644 index 0000000..69a6cac --- /dev/null +++ b/omni_python_sdk/models/connections_schedules_delete_connections_schedules_delete_response.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse") + + +@_attrs_define +class ConnectionsSchedulesDeleteConnectionsSchedulesDeleteResponse: + """Delete schedule response + + Attributes: + success (bool): Whether the operation succeeded Example: True. + """ + + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + success = d.pop("success") + + connections_schedules_delete_connections_schedules_delete_response = cls( + success=success, + ) + + connections_schedules_delete_connections_schedules_delete_response.additional_properties = d + return connections_schedules_delete_connections_schedules_delete_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_schedules_get_connections_schedules_get_response.py b/omni_python_sdk/models/connections_schedules_get_connections_schedules_get_response.py new file mode 100644 index 0000000..1570dbf --- /dev/null +++ b/omni_python_sdk/models/connections_schedules_get_connections_schedules_get_response.py @@ -0,0 +1,136 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsSchedulesGetConnectionsSchedulesGetResponse") + + +@_attrs_define +class ConnectionsSchedulesGetConnectionsSchedulesGetResponse: + """Get schedule response + + Attributes: + connection_id (UUID): Connection ID this schedule belongs to Example: 550e8400-e29b-41d4-a716-446655440000. + created_at (str): Schedule creation timestamp (ISO 8601) Example: 2024-01-15T10:30:00Z. + description (str): Human-readable schedule description Example: Runs daily at 2:00 AM EST. + disabled_at (None | str): Timestamp when schedule was disabled (ISO 8601) + hard_refresh (bool): When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds + the schema model. When false, it performs a soft refresh that merges newly generated views with the existing + model. + schedule (str): AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See + https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html Example: 0 2 * * ? *. + schedule_id (UUID): Unique schedule identifier Example: 550e8400-e29b-41d4-a716-446655440001. + timezone (str): IANA timezone for schedule execution Example: America/New_York. + updated_at (str): Schedule last update timestamp (ISO 8601) Example: 2024-01-15T10:30:00Z. + """ + + connection_id: UUID + created_at: str + description: str + disabled_at: None | str + hard_refresh: bool + schedule: str + schedule_id: UUID + timezone: str + updated_at: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + connection_id = str(self.connection_id) + + created_at = self.created_at + + description = self.description + + disabled_at: None | str + disabled_at = self.disabled_at + + hard_refresh = self.hard_refresh + + schedule = self.schedule + + schedule_id = str(self.schedule_id) + + timezone = self.timezone + + updated_at = self.updated_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "connectionId": connection_id, + "createdAt": created_at, + "description": description, + "disabledAt": disabled_at, + "hardRefresh": hard_refresh, + "schedule": schedule, + "scheduleId": schedule_id, + "timezone": timezone, + "updatedAt": updated_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + connection_id = UUID(d.pop("connectionId")) + + created_at = d.pop("createdAt") + + description = d.pop("description") + + def _parse_disabled_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + disabled_at = _parse_disabled_at(d.pop("disabledAt")) + + hard_refresh = d.pop("hardRefresh") + + schedule = d.pop("schedule") + + schedule_id = UUID(d.pop("scheduleId")) + + timezone = d.pop("timezone") + + updated_at = d.pop("updatedAt") + + connections_schedules_get_connections_schedules_get_response = cls( + connection_id=connection_id, + created_at=created_at, + description=description, + disabled_at=disabled_at, + hard_refresh=hard_refresh, + schedule=schedule, + schedule_id=schedule_id, + timezone=timezone, + updated_at=updated_at, + ) + + connections_schedules_get_connections_schedules_get_response.additional_properties = d + return connections_schedules_get_connections_schedules_get_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_schedules_list_connections_schedules_list_response.py b/omni_python_sdk/models/connections_schedules_list_connections_schedules_list_response.py new file mode 100644 index 0000000..be53df2 --- /dev/null +++ b/omni_python_sdk/models/connections_schedules_list_connections_schedules_list_response.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.connections_schedules_list_connections_schedules_list_response_connection_schedule import ( + ConnectionsSchedulesListConnectionsSchedulesListResponseConnectionSchedule, + ) + + +T = TypeVar("T", bound="ConnectionsSchedulesListConnectionsSchedulesListResponse") + + +@_attrs_define +class ConnectionsSchedulesListConnectionsSchedulesListResponse: + """List schedules response + + Attributes: + schedules (list[ConnectionsSchedulesListConnectionsSchedulesListResponseConnectionSchedule]): List of schema + refresh schedules + """ + + schedules: list[ConnectionsSchedulesListConnectionsSchedulesListResponseConnectionSchedule] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + schedules = [] + for schedules_item_data in self.schedules: + schedules_item = schedules_item_data.to_dict() + schedules.append(schedules_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "schedules": schedules, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.connections_schedules_list_connections_schedules_list_response_connection_schedule import ( + ConnectionsSchedulesListConnectionsSchedulesListResponseConnectionSchedule, + ) + + d = dict(src_dict) + schedules = [] + _schedules = d.pop("schedules") + for schedules_item_data in _schedules: + schedules_item = ConnectionsSchedulesListConnectionsSchedulesListResponseConnectionSchedule.from_dict( + schedules_item_data + ) + + schedules.append(schedules_item) + + connections_schedules_list_connections_schedules_list_response = cls( + schedules=schedules, + ) + + connections_schedules_list_connections_schedules_list_response.additional_properties = d + return connections_schedules_list_connections_schedules_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_schedules_list_connections_schedules_list_response_connection_schedule.py b/omni_python_sdk/models/connections_schedules_list_connections_schedules_list_response_connection_schedule.py new file mode 100644 index 0000000..e3e9da1 --- /dev/null +++ b/omni_python_sdk/models/connections_schedules_list_connections_schedules_list_response_connection_schedule.py @@ -0,0 +1,136 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsSchedulesListConnectionsSchedulesListResponseConnectionSchedule") + + +@_attrs_define +class ConnectionsSchedulesListConnectionsSchedulesListResponseConnectionSchedule: + """Schema refresh schedule object + + Attributes: + connection_id (UUID): Connection ID this schedule belongs to Example: 550e8400-e29b-41d4-a716-446655440000. + created_at (str): Schedule creation timestamp (ISO 8601) Example: 2024-01-15T10:30:00Z. + description (str): Human-readable schedule description Example: Runs daily at 2:00 AM EST. + disabled_at (None | str): Timestamp when schedule was disabled (ISO 8601) + hard_refresh (bool): When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds + the schema model. When false, it performs a soft refresh that merges newly generated views with the existing + model. + schedule (str): AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See + https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html Example: 0 2 * * ? *. + schedule_id (UUID): Unique schedule identifier Example: 550e8400-e29b-41d4-a716-446655440001. + timezone (str): IANA timezone for schedule execution Example: America/New_York. + updated_at (str): Schedule last update timestamp (ISO 8601) Example: 2024-01-15T10:30:00Z. + """ + + connection_id: UUID + created_at: str + description: str + disabled_at: None | str + hard_refresh: bool + schedule: str + schedule_id: UUID + timezone: str + updated_at: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + connection_id = str(self.connection_id) + + created_at = self.created_at + + description = self.description + + disabled_at: None | str + disabled_at = self.disabled_at + + hard_refresh = self.hard_refresh + + schedule = self.schedule + + schedule_id = str(self.schedule_id) + + timezone = self.timezone + + updated_at = self.updated_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "connectionId": connection_id, + "createdAt": created_at, + "description": description, + "disabledAt": disabled_at, + "hardRefresh": hard_refresh, + "schedule": schedule, + "scheduleId": schedule_id, + "timezone": timezone, + "updatedAt": updated_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + connection_id = UUID(d.pop("connectionId")) + + created_at = d.pop("createdAt") + + description = d.pop("description") + + def _parse_disabled_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + disabled_at = _parse_disabled_at(d.pop("disabledAt")) + + hard_refresh = d.pop("hardRefresh") + + schedule = d.pop("schedule") + + schedule_id = UUID(d.pop("scheduleId")) + + timezone = d.pop("timezone") + + updated_at = d.pop("updatedAt") + + connections_schedules_list_connections_schedules_list_response_connection_schedule = cls( + connection_id=connection_id, + created_at=created_at, + description=description, + disabled_at=disabled_at, + hard_refresh=hard_refresh, + schedule=schedule, + schedule_id=schedule_id, + timezone=timezone, + updated_at=updated_at, + ) + + connections_schedules_list_connections_schedules_list_response_connection_schedule.additional_properties = d + return connections_schedules_list_connections_schedules_list_response_connection_schedule + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_schedules_update_connections_schedules_update_body.py b/omni_python_sdk/models/connections_schedules_update_connections_schedules_update_body.py new file mode 100644 index 0000000..6fe0bb6 --- /dev/null +++ b/omni_python_sdk/models/connections_schedules_update_connections_schedules_update_body.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody") + + +@_attrs_define +class ConnectionsSchedulesUpdateConnectionsSchedulesUpdateBody: + """Request body for updating a schema refresh schedule + + Attributes: + schedule (str): AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See + https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html Example: 0 2 * * ? *. + timezone (str): IANA timezone for schedule execution Example: America/New_York. + hard_refresh (bool | Unset): When true, the scheduled refresh performs a hard refresh that fully discards and + rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated + views with the existing model. Default: False. + """ + + schedule: str + timezone: str + hard_refresh: bool | Unset = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + schedule = self.schedule + + timezone = self.timezone + + hard_refresh = self.hard_refresh + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "schedule": schedule, + "timezone": timezone, + } + ) + if hard_refresh is not UNSET: + field_dict["hardRefresh"] = hard_refresh + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + schedule = d.pop("schedule") + + timezone = d.pop("timezone") + + hard_refresh = d.pop("hardRefresh", UNSET) + + connections_schedules_update_connections_schedules_update_body = cls( + schedule=schedule, + timezone=timezone, + hard_refresh=hard_refresh, + ) + + connections_schedules_update_connections_schedules_update_body.additional_properties = d + return connections_schedules_update_connections_schedules_update_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_schedules_update_connections_schedules_update_response.py b/omni_python_sdk/models/connections_schedules_update_connections_schedules_update_response.py new file mode 100644 index 0000000..de99ef5 --- /dev/null +++ b/omni_python_sdk/models/connections_schedules_update_connections_schedules_update_response.py @@ -0,0 +1,136 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse") + + +@_attrs_define +class ConnectionsSchedulesUpdateConnectionsSchedulesUpdateResponse: + """Updated schedule response + + Attributes: + connection_id (UUID): Connection ID this schedule belongs to Example: 550e8400-e29b-41d4-a716-446655440000. + created_at (str): Schedule creation timestamp (ISO 8601) Example: 2024-01-15T10:30:00Z. + description (str): Human-readable schedule description Example: Runs daily at 2:00 AM EST. + disabled_at (None | str): Timestamp when schedule was disabled (ISO 8601) + hard_refresh (bool): When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds + the schema model. When false, it performs a soft refresh that merges newly generated views with the existing + model. + schedule (str): AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See + https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html Example: 0 2 * * ? *. + schedule_id (UUID): Unique schedule identifier Example: 550e8400-e29b-41d4-a716-446655440001. + timezone (str): IANA timezone for schedule execution Example: America/New_York. + updated_at (str): Schedule last update timestamp (ISO 8601) Example: 2024-01-15T10:30:00Z. + """ + + connection_id: UUID + created_at: str + description: str + disabled_at: None | str + hard_refresh: bool + schedule: str + schedule_id: UUID + timezone: str + updated_at: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + connection_id = str(self.connection_id) + + created_at = self.created_at + + description = self.description + + disabled_at: None | str + disabled_at = self.disabled_at + + hard_refresh = self.hard_refresh + + schedule = self.schedule + + schedule_id = str(self.schedule_id) + + timezone = self.timezone + + updated_at = self.updated_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "connectionId": connection_id, + "createdAt": created_at, + "description": description, + "disabledAt": disabled_at, + "hardRefresh": hard_refresh, + "schedule": schedule, + "scheduleId": schedule_id, + "timezone": timezone, + "updatedAt": updated_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + connection_id = UUID(d.pop("connectionId")) + + created_at = d.pop("createdAt") + + description = d.pop("description") + + def _parse_disabled_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + disabled_at = _parse_disabled_at(d.pop("disabledAt")) + + hard_refresh = d.pop("hardRefresh") + + schedule = d.pop("schedule") + + schedule_id = UUID(d.pop("scheduleId")) + + timezone = d.pop("timezone") + + updated_at = d.pop("updatedAt") + + connections_schedules_update_connections_schedules_update_response = cls( + connection_id=connection_id, + created_at=created_at, + description=description, + disabled_at=disabled_at, + hard_refresh=hard_refresh, + schedule=schedule, + schedule_id=schedule_id, + timezone=timezone, + updated_at=updated_at, + ) + + connections_schedules_update_connections_schedules_update_response.additional_properties = d + return connections_schedules_update_connections_schedules_update_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_update_connections_update_body.py b/omni_python_sdk/models/connections_update_connections_update_body.py new file mode 100644 index 0000000..15add50 --- /dev/null +++ b/omni_python_sdk/models/connections_update_connections_update_body.py @@ -0,0 +1,135 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.connections_update_connections_update_body_environment_user_attribute_type_0 import ( + ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0, + ) + + +T = TypeVar("T", bound="ConnectionsUpdateConnectionsUpdateBody") + + +@_attrs_define +class ConnectionsUpdateConnectionsUpdateBody: + """Request body for updating connection attributes and credentials. At least one field must be provided. + + Attributes: + base_role (str | Unset): Default role to assign to this connection Example: QUERIER. + environment_user_attribute (ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0 | None | Unset): + User attribute settings for connection environments + password_unencrypted (str | Unset): New password or service account key. For BigQuery, this must be the JSON + service account key file content. + private_key (str | Unset): RSA private key for keypair authentication (Snowflake only). Must be PEM-encoded + PKCS#8 format, minimum 2048-bit. + """ + + base_role: str | Unset = UNSET + environment_user_attribute: ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0 | None | Unset = ( + UNSET + ) + password_unencrypted: str | Unset = UNSET + private_key: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.connections_update_connections_update_body_environment_user_attribute_type_0 import ( + ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0, + ) + + base_role = self.base_role + + environment_user_attribute: dict[str, Any] | None | Unset + if isinstance(self.environment_user_attribute, Unset): + environment_user_attribute = UNSET + elif isinstance( + self.environment_user_attribute, ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0 + ): + environment_user_attribute = self.environment_user_attribute.to_dict() + else: + environment_user_attribute = self.environment_user_attribute + + password_unencrypted = self.password_unencrypted + + private_key = self.private_key + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if base_role is not UNSET: + field_dict["baseRole"] = base_role + if environment_user_attribute is not UNSET: + field_dict["environmentUserAttribute"] = environment_user_attribute + if password_unencrypted is not UNSET: + field_dict["passwordUnencrypted"] = password_unencrypted + if private_key is not UNSET: + field_dict["privateKey"] = private_key + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.connections_update_connections_update_body_environment_user_attribute_type_0 import ( + ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0, + ) + + d = dict(src_dict) + base_role = d.pop("baseRole", UNSET) + + def _parse_environment_user_attribute( + data: object, + ) -> ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0 | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + environment_user_attribute_type_0 = ( + ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0.from_dict(data) + ) + + return environment_user_attribute_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0 | None | Unset, data) + + environment_user_attribute = _parse_environment_user_attribute(d.pop("environmentUserAttribute", UNSET)) + + password_unencrypted = d.pop("passwordUnencrypted", UNSET) + + private_key = d.pop("privateKey", UNSET) + + connections_update_connections_update_body = cls( + base_role=base_role, + environment_user_attribute=environment_user_attribute, + password_unencrypted=password_unencrypted, + private_key=private_key, + ) + + connections_update_connections_update_body.additional_properties = d + return connections_update_connections_update_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_update_connections_update_body_environment_user_attribute_type_0.py b/omni_python_sdk/models/connections_update_connections_update_body_environment_user_attribute_type_0.py new file mode 100644 index 0000000..b923707 --- /dev/null +++ b/omni_python_sdk/models/connections_update_connections_update_body_environment_user_attribute_type_0.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0") + + +@_attrs_define +class ConnectionsUpdateConnectionsUpdateBodyEnvironmentUserAttributeType0: + """User attribute settings for connection environments + + Attributes: + attribute_name (str): Name of the user attribute for environment selection Example: region. + default_values (list[str] | None): Default values for the user attribute Example: ['us-east', 'us-west']. + """ + + attribute_name: str + default_values: list[str] | None + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + attribute_name = self.attribute_name + + default_values: list[str] | None + if isinstance(self.default_values, list): + default_values = self.default_values + + else: + default_values = self.default_values + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "attributeName": attribute_name, + "defaultValues": default_values, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + attribute_name = d.pop("attributeName") + + def _parse_default_values(data: object) -> list[str] | None: + if data is None: + return data + try: + if not isinstance(data, list): + raise TypeError() + default_values_type_0 = cast(list[str], data) + + return default_values_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(list[str] | None, data) + + default_values = _parse_default_values(d.pop("defaultValues")) + + connections_update_connections_update_body_environment_user_attribute_type_0 = cls( + attribute_name=attribute_name, + default_values=default_values, + ) + + connections_update_connections_update_body_environment_user_attribute_type_0.additional_properties = d + return connections_update_connections_update_body_environment_user_attribute_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/connections_update_connections_update_response.py b/omni_python_sdk/models/connections_update_connections_update_response.py new file mode 100644 index 0000000..cf71415 --- /dev/null +++ b/omni_python_sdk/models/connections_update_connections_update_response.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ConnectionsUpdateConnectionsUpdateResponse") + + +@_attrs_define +class ConnectionsUpdateConnectionsUpdateResponse: + """Update connection response + + Attributes: + message (str): Status message describing what was updated Example: Updated connection default role.. + success (bool): Whether the operation succeeded Example: True. + """ + + message: str + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + success = d.pop("success") + + connections_update_connections_update_response = cls( + message=message, + success=success, + ) + + connections_update_connections_update_response.additional_properties = d + return connections_update_connections_update_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/containers_item.py b/omni_python_sdk/models/containers_item.py new file mode 100644 index 0000000..ae61603 --- /dev/null +++ b/omni_python_sdk/models/containers_item.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ContainersItem") + + +@_attrs_define +class ContainersItem: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + containers_item = cls() + + containers_item.additional_properties = d + return containers_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/content_filter_mode.py b/omni_python_sdk/models/content_filter_mode.py new file mode 100644 index 0000000..a629f03 --- /dev/null +++ b/omni_python_sdk/models/content_filter_mode.py @@ -0,0 +1,15 @@ +from typing import Literal + +ContentFilterMode = Literal["ALL", "NO_ISSUES", "WITH_ISSUES"] + +CONTENT_FILTER_MODE_VALUES: set[ContentFilterMode] = { + "ALL", + "NO_ISSUES", + "WITH_ISSUES", +} + + +def check_content_filter_mode(value: str) -> ContentFilterMode: + if value in CONTENT_FILTER_MODE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {CONTENT_FILTER_MODE_VALUES!r}") diff --git a/omni_python_sdk/models/content_list_response.py b/omni_python_sdk/models/content_list_response.py new file mode 100644 index 0000000..dc5d39b --- /dev/null +++ b/omni_python_sdk/models/content_list_response.py @@ -0,0 +1,112 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.content_list_response_records_item_type_0 import ContentListResponseRecordsItemType0 + from ..models.content_list_response_records_item_type_1 import ContentListResponseRecordsItemType1 + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="ContentListResponse") + + +@_attrs_define +class ContentListResponse: + """ + Attributes: + page_info (PageInfo): + records (list[ContentListResponseRecordsItemType0 | ContentListResponseRecordsItemType1]): + """ + + page_info: PageInfo + records: list[ContentListResponseRecordsItemType0 | ContentListResponseRecordsItemType1] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.content_list_response_records_item_type_0 import ContentListResponseRecordsItemType0 + + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item: dict[str, Any] + if isinstance(records_item_data, ContentListResponseRecordsItemType0): + records_item = records_item_data.to_dict() + else: + records_item = records_item_data.to_dict() + + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.content_list_response_records_item_type_0 import ContentListResponseRecordsItemType0 + from ..models.content_list_response_records_item_type_1 import ContentListResponseRecordsItemType1 + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + + def _parse_records_item( + data: object, + ) -> ContentListResponseRecordsItemType0 | ContentListResponseRecordsItemType1: + try: + if not isinstance(data, dict): + raise TypeError() + records_item_type_0 = ContentListResponseRecordsItemType0.from_dict(data) + + return records_item_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + records_item_type_1 = ContentListResponseRecordsItemType1.from_dict(data) + + return records_item_type_1 + + records_item = _parse_records_item(records_item_data) + + records.append(records_item) + + content_list_response = cls( + page_info=page_info, + records=records, + ) + + content_list_response.additional_properties = d + return content_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/content_list_response_records_item_type_0.py b/omni_python_sdk/models/content_list_response_records_item_type_0.py new file mode 100644 index 0000000..37cee1a --- /dev/null +++ b/omni_python_sdk/models/content_list_response_records_item_type_0.py @@ -0,0 +1,301 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.content_list_response_records_item_type_0_type import ( + ContentListResponseRecordsItemType0Type, + check_content_list_response_records_item_type_0_type, +) +from ..models.content_share_scope import ContentShareScope, check_content_share_scope +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.api_document_count import ApiDocumentCount + from ..models.internal_folder_type_0 import InternalFolderType0 + from ..models.owner_internal import OwnerInternal + + +T = TypeVar("T", bound="ContentListResponseRecordsItemType0") + + +@_attrs_define +class ContentListResponseRecordsItemType0: + """ + Attributes: + name (str): Content name + owner (OwnerInternal): Content owner + scope (ContentShareScope): Content access scope + connection_id (str): Connection ID + deleted (bool): Whether document is deleted + folder (InternalFolderType0 | None): Parent folder + has_app (bool): Whether document has an app + has_dashboard (bool): Whether document has a dashboard + identifier (str): Document identifier + updated_at (datetime.datetime | None): Last updated timestamp + url (str): URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an + app, otherwise the workbook URL. Example: https://org.omni.co/dashboards/abc123. + type_ (ContentListResponseRecordsItemType0Type): + field_count (ApiDocumentCount | Unset): Document counts + description (None | str | Unset): Document description + labels (list[str] | Unset): Applied labels + last_viewed_at (datetime.datetime | None | Unset): Last time the dashboard was viewed + visits (float | None | Unset): Number of dashboard visits + """ + + name: str + owner: OwnerInternal + scope: ContentShareScope + connection_id: str + deleted: bool + folder: InternalFolderType0 | None + has_app: bool + has_dashboard: bool + identifier: str + updated_at: datetime.datetime | None + url: str + type_: ContentListResponseRecordsItemType0Type + field_count: ApiDocumentCount | Unset = UNSET + description: None | str | Unset = UNSET + labels: list[str] | Unset = UNSET + last_viewed_at: datetime.datetime | None | Unset = UNSET + visits: float | None | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.internal_folder_type_0 import InternalFolderType0 + + name = self.name + + owner = self.owner.to_dict() + + scope: str = self.scope + + connection_id = self.connection_id + + deleted = self.deleted + + folder: dict[str, Any] | None + if isinstance(self.folder, InternalFolderType0): + folder = self.folder.to_dict() + else: + folder = self.folder + + has_app = self.has_app + + has_dashboard = self.has_dashboard + + identifier = self.identifier + + updated_at: None | str + if isinstance(self.updated_at, datetime.datetime): + updated_at = self.updated_at.isoformat() + else: + updated_at = self.updated_at + + url = self.url + + type_: str = self.type_ + + field_count: dict[str, Any] | Unset = UNSET + if not isinstance(self.field_count, Unset): + field_count = self.field_count.to_dict() + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + labels: list[str] | Unset = UNSET + if not isinstance(self.labels, Unset): + labels = self.labels + + last_viewed_at: None | str | Unset + if isinstance(self.last_viewed_at, Unset): + last_viewed_at = UNSET + elif isinstance(self.last_viewed_at, datetime.datetime): + last_viewed_at = self.last_viewed_at.isoformat() + else: + last_viewed_at = self.last_viewed_at + + visits: float | None | Unset + if isinstance(self.visits, Unset): + visits = UNSET + else: + visits = self.visits + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "owner": owner, + "scope": scope, + "connectionId": connection_id, + "deleted": deleted, + "folder": folder, + "hasApp": has_app, + "hasDashboard": has_dashboard, + "identifier": identifier, + "updatedAt": updated_at, + "url": url, + "type": type_, + } + ) + if field_count is not UNSET: + field_dict["_count"] = field_count + if description is not UNSET: + field_dict["description"] = description + if labels is not UNSET: + field_dict["labels"] = labels + if last_viewed_at is not UNSET: + field_dict["lastViewedAt"] = last_viewed_at + if visits is not UNSET: + field_dict["visits"] = visits + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.api_document_count import ApiDocumentCount + from ..models.internal_folder_type_0 import InternalFolderType0 + from ..models.owner_internal import OwnerInternal + + d = dict(src_dict) + name = d.pop("name") + + owner = OwnerInternal.from_dict(d.pop("owner")) + + scope = check_content_share_scope(d.pop("scope")) + + connection_id = d.pop("connectionId") + + deleted = d.pop("deleted") + + def _parse_folder(data: object) -> InternalFolderType0 | None: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_internal_folder_type_0 = InternalFolderType0.from_dict(data) + + return componentsschemas_internal_folder_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(InternalFolderType0 | None, data) + + folder = _parse_folder(d.pop("folder")) + + has_app = d.pop("hasApp") + + has_dashboard = d.pop("hasDashboard") + + identifier = d.pop("identifier") + + def _parse_updated_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + updated_at_type_0 = datetime.datetime.fromisoformat(data) + + return updated_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + updated_at = _parse_updated_at(d.pop("updatedAt")) + + url = d.pop("url") + + type_ = check_content_list_response_records_item_type_0_type(d.pop("type")) + + _field_count = d.pop("_count", UNSET) + field_count: ApiDocumentCount | Unset + if isinstance(_field_count, Unset): + field_count = UNSET + else: + field_count = ApiDocumentCount.from_dict(_field_count) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + labels = cast(list[str], d.pop("labels", UNSET)) + + def _parse_last_viewed_at(data: object) -> datetime.datetime | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + last_viewed_at_type_0 = datetime.datetime.fromisoformat(data) + + return last_viewed_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None | Unset, data) + + last_viewed_at = _parse_last_viewed_at(d.pop("lastViewedAt", UNSET)) + + def _parse_visits(data: object) -> float | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(float | None | Unset, data) + + visits = _parse_visits(d.pop("visits", UNSET)) + + content_list_response_records_item_type_0 = cls( + name=name, + owner=owner, + scope=scope, + connection_id=connection_id, + deleted=deleted, + folder=folder, + has_app=has_app, + has_dashboard=has_dashboard, + identifier=identifier, + updated_at=updated_at, + url=url, + type_=type_, + field_count=field_count, + description=description, + labels=labels, + last_viewed_at=last_viewed_at, + visits=visits, + ) + + content_list_response_records_item_type_0.additional_properties = d + return content_list_response_records_item_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/content_list_response_records_item_type_0_type.py b/omni_python_sdk/models/content_list_response_records_item_type_0_type.py new file mode 100644 index 0000000..34e6533 --- /dev/null +++ b/omni_python_sdk/models/content_list_response_records_item_type_0_type.py @@ -0,0 +1,15 @@ +from typing import Literal + +ContentListResponseRecordsItemType0Type = Literal["document"] + +CONTENT_LIST_RESPONSE_RECORDS_ITEM_TYPE_0_TYPE_VALUES: set[ContentListResponseRecordsItemType0Type] = { + "document", +} + + +def check_content_list_response_records_item_type_0_type(value: str) -> ContentListResponseRecordsItemType0Type: + if value in CONTENT_LIST_RESPONSE_RECORDS_ITEM_TYPE_0_TYPE_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CONTENT_LIST_RESPONSE_RECORDS_ITEM_TYPE_0_TYPE_VALUES!r}" + ) diff --git a/omni_python_sdk/models/content_list_response_records_item_type_1.py b/omni_python_sdk/models/content_list_response_records_item_type_1.py new file mode 100644 index 0000000..9595108 --- /dev/null +++ b/omni_python_sdk/models/content_list_response_records_item_type_1.py @@ -0,0 +1,154 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.content_list_response_records_item_type_1_scope import ( + ContentListResponseRecordsItemType1Scope, + check_content_list_response_records_item_type_1_scope, +) +from ..models.content_list_response_records_item_type_1_type import ( + ContentListResponseRecordsItemType1Type, + check_content_list_response_records_item_type_1_type, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.content_list_response_records_item_type_1_count import ContentListResponseRecordsItemType1Count + from ..models.content_list_response_records_item_type_1_owner import ContentListResponseRecordsItemType1Owner + + +T = TypeVar("T", bound="ContentListResponseRecordsItemType1") + + +@_attrs_define +class ContentListResponseRecordsItemType1: + """ + Attributes: + id (str): Unique identifier + name (str): Content name + owner (ContentListResponseRecordsItemType1Owner): Content owner + scope (ContentListResponseRecordsItemType1Scope): Content access scope + path (str): Full path to the folder Example: sales-reports/q1-2026. + url (str): URL to view the folder in the Omni UI. Example: https://org.omni.co/f/sales-reports. + type_ (ContentListResponseRecordsItemType1Type): + field_count (ContentListResponseRecordsItemType1Count | Unset): Folder counts + labels (list[str] | Unset): Labels + """ + + id: str + name: str + owner: ContentListResponseRecordsItemType1Owner + scope: ContentListResponseRecordsItemType1Scope + path: str + url: str + type_: ContentListResponseRecordsItemType1Type + field_count: ContentListResponseRecordsItemType1Count | Unset = UNSET + labels: list[str] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + owner = self.owner.to_dict() + + scope: str = self.scope + + path = self.path + + url = self.url + + type_: str = self.type_ + + field_count: dict[str, Any] | Unset = UNSET + if not isinstance(self.field_count, Unset): + field_count = self.field_count.to_dict() + + labels: list[str] | Unset = UNSET + if not isinstance(self.labels, Unset): + labels = self.labels + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + "owner": owner, + "scope": scope, + "path": path, + "url": url, + "type": type_, + } + ) + if field_count is not UNSET: + field_dict["_count"] = field_count + if labels is not UNSET: + field_dict["labels"] = labels + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.content_list_response_records_item_type_1_count import ContentListResponseRecordsItemType1Count + from ..models.content_list_response_records_item_type_1_owner import ContentListResponseRecordsItemType1Owner + + d = dict(src_dict) + id = d.pop("id") + + name = d.pop("name") + + owner = ContentListResponseRecordsItemType1Owner.from_dict(d.pop("owner")) + + scope = check_content_list_response_records_item_type_1_scope(d.pop("scope")) + + path = d.pop("path") + + url = d.pop("url") + + type_ = check_content_list_response_records_item_type_1_type(d.pop("type")) + + _field_count = d.pop("_count", UNSET) + field_count: ContentListResponseRecordsItemType1Count | Unset + if isinstance(_field_count, Unset): + field_count = UNSET + else: + field_count = ContentListResponseRecordsItemType1Count.from_dict(_field_count) + + labels = cast(list[str], d.pop("labels", UNSET)) + + content_list_response_records_item_type_1 = cls( + id=id, + name=name, + owner=owner, + scope=scope, + path=path, + url=url, + type_=type_, + field_count=field_count, + labels=labels, + ) + + content_list_response_records_item_type_1.additional_properties = d + return content_list_response_records_item_type_1 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/content_list_response_records_item_type_1_count.py b/omni_python_sdk/models/content_list_response_records_item_type_1_count.py new file mode 100644 index 0000000..126065d --- /dev/null +++ b/omni_python_sdk/models/content_list_response_records_item_type_1_count.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ContentListResponseRecordsItemType1Count") + + +@_attrs_define +class ContentListResponseRecordsItemType1Count: + """Folder counts + + Attributes: + documents (float): Number of documents + favorites (float): Number of users who favorited + """ + + documents: float + favorites: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + documents = self.documents + + favorites = self.favorites + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "documents": documents, + "favorites": favorites, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + documents = d.pop("documents") + + favorites = d.pop("favorites") + + content_list_response_records_item_type_1_count = cls( + documents=documents, + favorites=favorites, + ) + + content_list_response_records_item_type_1_count.additional_properties = d + return content_list_response_records_item_type_1_count + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/content_list_response_records_item_type_1_owner.py b/omni_python_sdk/models/content_list_response_records_item_type_1_owner.py new file mode 100644 index 0000000..c78a024 --- /dev/null +++ b/omni_python_sdk/models/content_list_response_records_item_type_1_owner.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ContentListResponseRecordsItemType1Owner") + + +@_attrs_define +class ContentListResponseRecordsItemType1Owner: + """Content owner + + Attributes: + id (str): User ID of the owner + name (str): Name of the owner + """ + + id: str + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + name = d.pop("name") + + content_list_response_records_item_type_1_owner = cls( + id=id, + name=name, + ) + + content_list_response_records_item_type_1_owner.additional_properties = d + return content_list_response_records_item_type_1_owner + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/content_list_response_records_item_type_1_scope.py b/omni_python_sdk/models/content_list_response_records_item_type_1_scope.py new file mode 100644 index 0000000..dcf2148 --- /dev/null +++ b/omni_python_sdk/models/content_list_response_records_item_type_1_scope.py @@ -0,0 +1,16 @@ +from typing import Literal + +ContentListResponseRecordsItemType1Scope = Literal["organization", "restricted"] + +CONTENT_LIST_RESPONSE_RECORDS_ITEM_TYPE_1_SCOPE_VALUES: set[ContentListResponseRecordsItemType1Scope] = { + "organization", + "restricted", +} + + +def check_content_list_response_records_item_type_1_scope(value: str) -> ContentListResponseRecordsItemType1Scope: + if value in CONTENT_LIST_RESPONSE_RECORDS_ITEM_TYPE_1_SCOPE_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CONTENT_LIST_RESPONSE_RECORDS_ITEM_TYPE_1_SCOPE_VALUES!r}" + ) diff --git a/omni_python_sdk/models/content_list_response_records_item_type_1_type.py b/omni_python_sdk/models/content_list_response_records_item_type_1_type.py new file mode 100644 index 0000000..17ac11a --- /dev/null +++ b/omni_python_sdk/models/content_list_response_records_item_type_1_type.py @@ -0,0 +1,15 @@ +from typing import Literal + +ContentListResponseRecordsItemType1Type = Literal["folder"] + +CONTENT_LIST_RESPONSE_RECORDS_ITEM_TYPE_1_TYPE_VALUES: set[ContentListResponseRecordsItemType1Type] = { + "folder", +} + + +def check_content_list_response_records_item_type_1_type(value: str) -> ContentListResponseRecordsItemType1Type: + if value in CONTENT_LIST_RESPONSE_RECORDS_ITEM_TYPE_1_TYPE_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CONTENT_LIST_RESPONSE_RECORDS_ITEM_TYPE_1_TYPE_VALUES!r}" + ) diff --git a/omni_python_sdk/models/content_list_scope.py b/omni_python_sdk/models/content_list_scope.py new file mode 100644 index 0000000..c46e216 --- /dev/null +++ b/omni_python_sdk/models/content_list_scope.py @@ -0,0 +1,14 @@ +from typing import Literal + +ContentListScope = Literal["organization", "restricted"] + +CONTENT_LIST_SCOPE_VALUES: set[ContentListScope] = { + "organization", + "restricted", +} + + +def check_content_list_scope(value: str) -> ContentListScope: + if value in CONTENT_LIST_SCOPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {CONTENT_LIST_SCOPE_VALUES!r}") diff --git a/omni_python_sdk/models/content_list_sort_direction.py b/omni_python_sdk/models/content_list_sort_direction.py new file mode 100644 index 0000000..07dd3f1 --- /dev/null +++ b/omni_python_sdk/models/content_list_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +ContentListSortDirection = Literal["asc", "desc"] + +CONTENT_LIST_SORT_DIRECTION_VALUES: set[ContentListSortDirection] = { + "asc", + "desc", +} + + +def check_content_list_sort_direction(value: str) -> ContentListSortDirection: + if value in CONTENT_LIST_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {CONTENT_LIST_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/content_list_sort_field.py b/omni_python_sdk/models/content_list_sort_field.py new file mode 100644 index 0000000..a822d68 --- /dev/null +++ b/omni_python_sdk/models/content_list_sort_field.py @@ -0,0 +1,14 @@ +from typing import Literal + +ContentListSortField = Literal["favorites", "name"] + +CONTENT_LIST_SORT_FIELD_VALUES: set[ContentListSortField] = { + "favorites", + "name", +} + + +def check_content_list_sort_field(value: str) -> ContentListSortField: + if value in CONTENT_LIST_SORT_FIELD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {CONTENT_LIST_SORT_FIELD_VALUES!r}") diff --git a/omni_python_sdk/models/content_share_scope.py b/omni_python_sdk/models/content_share_scope.py new file mode 100644 index 0000000..3524062 --- /dev/null +++ b/omni_python_sdk/models/content_share_scope.py @@ -0,0 +1,14 @@ +from typing import Literal + +ContentShareScope = Literal["organization", "restricted"] + +CONTENT_SHARE_SCOPE_VALUES: set[ContentShareScope] = { + "organization", + "restricted", +} + + +def check_content_share_scope(value: str) -> ContentShareScope: + if value in CONTENT_SHARE_SCOPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {CONTENT_SHARE_SCOPE_VALUES!r}") diff --git a/omni_python_sdk/models/control_patch_external.py b/omni_python_sdk/models/control_patch_external.py new file mode 100644 index 0000000..c73c09d --- /dev/null +++ b/omni_python_sdk/models/control_patch_external.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ControlPatchExternal") + + +@_attrs_define +class ControlPatchExternal: + """(Not statically modeled; use plain dicts.)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + control_patch_external = cls() + + control_patch_external.additional_properties = d + return control_patch_external + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/control_read_external.py b/omni_python_sdk/models/control_read_external.py new file mode 100644 index 0000000..d8fc432 --- /dev/null +++ b/omni_python_sdk/models/control_read_external.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ControlReadExternal") + + +@_attrs_define +class ControlReadExternal: + """(Not statically modeled; use plain dicts.)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + control_read_external = cls() + + control_read_external.additional_properties = d + return control_read_external + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/controls_patch_external.py b/omni_python_sdk/models/controls_patch_external.py new file mode 100644 index 0000000..0281965 --- /dev/null +++ b/omni_python_sdk/models/controls_patch_external.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ControlsPatchExternal") + + +@_attrs_define +class ControlsPatchExternal: + """(Not statically modeled; use plain dicts.)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + controls_patch_external = cls() + + controls_patch_external.additional_properties = d + return controls_patch_external + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/controls_read_external.py b/omni_python_sdk/models/controls_read_external.py new file mode 100644 index 0000000..0f975c2 --- /dev/null +++ b/omni_python_sdk/models/controls_read_external.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ControlsReadExternal") + + +@_attrs_define +class ControlsReadExternal: + """(Not statically modeled; use plain dicts.)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + controls_read_external = cls() + + controls_read_external.additional_properties = d + return controls_read_external + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/create_model_schema_base.py b/omni_python_sdk/models/create_model_schema_base.py new file mode 100644 index 0000000..cb3a67a --- /dev/null +++ b/omni_python_sdk/models/create_model_schema_base.py @@ -0,0 +1,211 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.create_model_schema_base_model_kind_type_0 import ( + CreateModelSchemaBaseModelKindType0, + check_create_model_schema_base_model_kind_type_0, +) +from ..models.create_model_schema_base_model_kind_type_1 import ( + CreateModelSchemaBaseModelKindType1, + check_create_model_schema_base_model_kind_type_1, +) +from ..models.create_model_schema_base_model_kind_type_2 import ( + CreateModelSchemaBaseModelKindType2, + check_create_model_schema_base_model_kind_type_2, +) +from ..models.create_model_schema_base_model_kind_type_3 import ( + CreateModelSchemaBaseModelKindType3, + check_create_model_schema_base_model_kind_type_3, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_model_schema_base_access_grants_item import CreateModelSchemaBaseAccessGrantsItem + + +T = TypeVar("T", bound="CreateModelSchemaBase") + + +@_attrs_define +class CreateModelSchemaBase: + """ + Attributes: + connection_id (str): Connection ID for the model + access_grants (list[CreateModelSchemaBaseAccessGrantsItem] | Unset): Access grants for the model + allow_as_workbook_base (bool | Unset): Allow this model as a workbook base + base_model_id (str | Unset): Base model ID for extension or branch models + model_kind (CreateModelSchemaBaseModelKindType0 | CreateModelSchemaBaseModelKindType1 | + CreateModelSchemaBaseModelKindType2 | CreateModelSchemaBaseModelKindType3 | Unset): Kind of model to create + Default: 'SCHEMA'. + model_name (str | Unset): Name for the model + uses_isolated_branches (bool | Unset): For SHARED_EXTENSION models, controls if branches are shown on extension + model page instead of parent shared model + """ + + connection_id: str + access_grants: list[CreateModelSchemaBaseAccessGrantsItem] | Unset = UNSET + allow_as_workbook_base: bool | Unset = UNSET + base_model_id: str | Unset = UNSET + model_kind: ( + CreateModelSchemaBaseModelKindType0 + | CreateModelSchemaBaseModelKindType1 + | CreateModelSchemaBaseModelKindType2 + | CreateModelSchemaBaseModelKindType3 + | Unset + ) = "SCHEMA" + model_name: str | Unset = UNSET + uses_isolated_branches: bool | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + connection_id = self.connection_id + + access_grants: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.access_grants, Unset): + access_grants = [] + for access_grants_item_data in self.access_grants: + access_grants_item = access_grants_item_data.to_dict() + access_grants.append(access_grants_item) + + allow_as_workbook_base = self.allow_as_workbook_base + + base_model_id = self.base_model_id + + model_kind: str | Unset + if isinstance(self.model_kind, Unset): + model_kind = UNSET + elif isinstance(self.model_kind, str): + model_kind = self.model_kind + elif isinstance(self.model_kind, str): + model_kind = self.model_kind + elif isinstance(self.model_kind, str): + model_kind = self.model_kind + else: + model_kind = self.model_kind + + model_name = self.model_name + + uses_isolated_branches = self.uses_isolated_branches + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "connectionId": connection_id, + } + ) + if access_grants is not UNSET: + field_dict["accessGrants"] = access_grants + if allow_as_workbook_base is not UNSET: + field_dict["allowAsWorkbookBase"] = allow_as_workbook_base + if base_model_id is not UNSET: + field_dict["baseModelId"] = base_model_id + if model_kind is not UNSET: + field_dict["modelKind"] = model_kind + if model_name is not UNSET: + field_dict["modelName"] = model_name + if uses_isolated_branches is not UNSET: + field_dict["usesIsolatedBranches"] = uses_isolated_branches + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.create_model_schema_base_access_grants_item import CreateModelSchemaBaseAccessGrantsItem + + d = dict(src_dict) + connection_id = d.pop("connectionId") + + _access_grants = d.pop("accessGrants", UNSET) + access_grants: list[CreateModelSchemaBaseAccessGrantsItem] | Unset = UNSET + if _access_grants is not UNSET: + access_grants = [] + for access_grants_item_data in _access_grants: + access_grants_item = CreateModelSchemaBaseAccessGrantsItem.from_dict(access_grants_item_data) + + access_grants.append(access_grants_item) + + allow_as_workbook_base = d.pop("allowAsWorkbookBase", UNSET) + + base_model_id = d.pop("baseModelId", UNSET) + + def _parse_model_kind( + data: object, + ) -> ( + CreateModelSchemaBaseModelKindType0 + | CreateModelSchemaBaseModelKindType1 + | CreateModelSchemaBaseModelKindType2 + | CreateModelSchemaBaseModelKindType3 + | Unset + ): + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + model_kind_type_0 = check_create_model_schema_base_model_kind_type_0(data) + + return model_kind_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, str): + raise TypeError() + model_kind_type_1 = check_create_model_schema_base_model_kind_type_1(data) + + return model_kind_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, str): + raise TypeError() + model_kind_type_2 = check_create_model_schema_base_model_kind_type_2(data) + + return model_kind_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, str): + raise TypeError() + model_kind_type_3 = check_create_model_schema_base_model_kind_type_3(data) + + return model_kind_type_3 + + model_kind = _parse_model_kind(d.pop("modelKind", UNSET)) + + model_name = d.pop("modelName", UNSET) + + uses_isolated_branches = d.pop("usesIsolatedBranches", UNSET) + + create_model_schema_base = cls( + connection_id=connection_id, + access_grants=access_grants, + allow_as_workbook_base=allow_as_workbook_base, + base_model_id=base_model_id, + model_kind=model_kind, + model_name=model_name, + uses_isolated_branches=uses_isolated_branches, + ) + + create_model_schema_base.additional_properties = d + return create_model_schema_base + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/create_model_schema_base_access_grants_item.py b/omni_python_sdk/models/create_model_schema_base_access_grants_item.py new file mode 100644 index 0000000..6bcf9c4 --- /dev/null +++ b/omni_python_sdk/models/create_model_schema_base_access_grants_item.py @@ -0,0 +1,126 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.create_model_schema_base_access_grants_item_code_comments import ( + CreateModelSchemaBaseAccessGrantsItemCodeComments, + ) + + +T = TypeVar("T", bound="CreateModelSchemaBaseAccessGrantsItem") + + +@_attrs_define +class CreateModelSchemaBaseAccessGrantsItem: + """ + Attributes: + access_boostable (bool): + name (str): + allowed_values (list[str] | Unset): + code_comments (CreateModelSchemaBaseAccessGrantsItemCodeComments | Unset): + ignored (bool | Unset): + user_attribute (str | Unset): + """ + + access_boostable: bool + name: str + allowed_values: list[str] | Unset = UNSET + code_comments: CreateModelSchemaBaseAccessGrantsItemCodeComments | Unset = UNSET + ignored: bool | Unset = UNSET + user_attribute: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + access_boostable = self.access_boostable + + name = self.name + + allowed_values: list[str] | Unset = UNSET + if not isinstance(self.allowed_values, Unset): + allowed_values = self.allowed_values + + code_comments: dict[str, Any] | Unset = UNSET + if not isinstance(self.code_comments, Unset): + code_comments = self.code_comments.to_dict() + + ignored = self.ignored + + user_attribute = self.user_attribute + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "accessBoostable": access_boostable, + "name": name, + } + ) + if allowed_values is not UNSET: + field_dict["allowedValues"] = allowed_values + if code_comments is not UNSET: + field_dict["codeComments"] = code_comments + if ignored is not UNSET: + field_dict["ignored"] = ignored + if user_attribute is not UNSET: + field_dict["userAttribute"] = user_attribute + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.create_model_schema_base_access_grants_item_code_comments import ( + CreateModelSchemaBaseAccessGrantsItemCodeComments, + ) + + d = dict(src_dict) + access_boostable = d.pop("accessBoostable") + + name = d.pop("name") + + allowed_values = cast(list[str], d.pop("allowedValues", UNSET)) + + _code_comments = d.pop("codeComments", UNSET) + code_comments: CreateModelSchemaBaseAccessGrantsItemCodeComments | Unset + if isinstance(_code_comments, Unset): + code_comments = UNSET + else: + code_comments = CreateModelSchemaBaseAccessGrantsItemCodeComments.from_dict(_code_comments) + + ignored = d.pop("ignored", UNSET) + + user_attribute = d.pop("userAttribute", UNSET) + + create_model_schema_base_access_grants_item = cls( + access_boostable=access_boostable, + name=name, + allowed_values=allowed_values, + code_comments=code_comments, + ignored=ignored, + user_attribute=user_attribute, + ) + + create_model_schema_base_access_grants_item.additional_properties = d + return create_model_schema_base_access_grants_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/create_model_schema_base_access_grants_item_code_comments.py b/omni_python_sdk/models/create_model_schema_base_access_grants_item_code_comments.py new file mode 100644 index 0000000..18596e6 --- /dev/null +++ b/omni_python_sdk/models/create_model_schema_base_access_grants_item_code_comments.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="CreateModelSchemaBaseAccessGrantsItemCodeComments") + + +@_attrs_define +class CreateModelSchemaBaseAccessGrantsItemCodeComments: + """ """ + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + create_model_schema_base_access_grants_item_code_comments = cls() + + create_model_schema_base_access_grants_item_code_comments.additional_properties = d + return create_model_schema_base_access_grants_item_code_comments + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/create_model_schema_base_model_kind_type_0.py b/omni_python_sdk/models/create_model_schema_base_model_kind_type_0.py new file mode 100644 index 0000000..466dec1 --- /dev/null +++ b/omni_python_sdk/models/create_model_schema_base_model_kind_type_0.py @@ -0,0 +1,15 @@ +from typing import Literal + +CreateModelSchemaBaseModelKindType0 = Literal["SCHEMA"] + +CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_0_VALUES: set[CreateModelSchemaBaseModelKindType0] = { + "SCHEMA", +} + + +def check_create_model_schema_base_model_kind_type_0(value: str) -> CreateModelSchemaBaseModelKindType0: + if value in CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_0_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_0_VALUES!r}" + ) diff --git a/omni_python_sdk/models/create_model_schema_base_model_kind_type_1.py b/omni_python_sdk/models/create_model_schema_base_model_kind_type_1.py new file mode 100644 index 0000000..bcd8f35 --- /dev/null +++ b/omni_python_sdk/models/create_model_schema_base_model_kind_type_1.py @@ -0,0 +1,15 @@ +from typing import Literal + +CreateModelSchemaBaseModelKindType1 = Literal["SHARED"] + +CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_1_VALUES: set[CreateModelSchemaBaseModelKindType1] = { + "SHARED", +} + + +def check_create_model_schema_base_model_kind_type_1(value: str) -> CreateModelSchemaBaseModelKindType1: + if value in CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/create_model_schema_base_model_kind_type_2.py b/omni_python_sdk/models/create_model_schema_base_model_kind_type_2.py new file mode 100644 index 0000000..4361245 --- /dev/null +++ b/omni_python_sdk/models/create_model_schema_base_model_kind_type_2.py @@ -0,0 +1,15 @@ +from typing import Literal + +CreateModelSchemaBaseModelKindType2 = Literal["SHARED_EXTENSION"] + +CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_2_VALUES: set[CreateModelSchemaBaseModelKindType2] = { + "SHARED_EXTENSION", +} + + +def check_create_model_schema_base_model_kind_type_2(value: str) -> CreateModelSchemaBaseModelKindType2: + if value in CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_2_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_2_VALUES!r}" + ) diff --git a/omni_python_sdk/models/create_model_schema_base_model_kind_type_3.py b/omni_python_sdk/models/create_model_schema_base_model_kind_type_3.py new file mode 100644 index 0000000..5bc3c17 --- /dev/null +++ b/omni_python_sdk/models/create_model_schema_base_model_kind_type_3.py @@ -0,0 +1,15 @@ +from typing import Literal + +CreateModelSchemaBaseModelKindType3 = Literal["BRANCH"] + +CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_3_VALUES: set[CreateModelSchemaBaseModelKindType3] = { + "BRANCH", +} + + +def check_create_model_schema_base_model_kind_type_3(value: str) -> CreateModelSchemaBaseModelKindType3: + if value in CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_3_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_3_VALUES!r}" + ) diff --git a/omni_python_sdk/models/dashboard_filters_response.py b/omni_python_sdk/models/dashboard_filters_response.py new file mode 100644 index 0000000..e30fa8a --- /dev/null +++ b/omni_python_sdk/models/dashboard_filters_response.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DashboardFiltersResponse") + + +@_attrs_define +class DashboardFiltersResponse: + """ + Attributes: + filter_order (list[str]): Ordered list of filter IDs defining display order Example: ['filter_abc123', + 'filter_def456']. + identifier (str): Dashboard identifier Example: 12db1a0a. + controls (Any | Unset): Control configuration object. Keys are control IDs, values contain controlType, + filterId, label, etc. + filters (Any | Unset): Filter configuration object. Keys are filter IDs, values contain fieldName, viewName, + kind, defaultValue, etc. + """ + + filter_order: list[str] + identifier: str + controls: Any | Unset = UNSET + filters: Any | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + filter_order = self.filter_order + + identifier = self.identifier + + controls = self.controls + + filters = self.filters + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "filterOrder": filter_order, + "identifier": identifier, + } + ) + if controls is not UNSET: + field_dict["controls"] = controls + if filters is not UNSET: + field_dict["filters"] = filters + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + filter_order = cast(list[str], d.pop("filterOrder")) + + identifier = d.pop("identifier") + + controls = d.pop("controls", UNSET) + + filters = d.pop("filters", UNSET) + + dashboard_filters_response = cls( + filter_order=filter_order, + identifier=identifier, + controls=controls, + filters=filters, + ) + + dashboard_filters_response.additional_properties = d + return dashboard_filters_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dashboards_download_body.py b/omni_python_sdk/models/dashboards_download_body.py new file mode 100644 index 0000000..11e5408 --- /dev/null +++ b/omni_python_sdk/models/dashboards_download_body.py @@ -0,0 +1,219 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define + +from ..models.dashboards_download_body_format import DashboardsDownloadBodyFormat, check_dashboards_download_body_format +from ..models.dashboards_download_body_paper_format import ( + DashboardsDownloadBodyPaperFormat, + check_dashboards_download_body_paper_format, +) +from ..models.dashboards_download_body_paper_orientation import ( + DashboardsDownloadBodyPaperOrientation, + check_dashboards_download_body_paper_orientation, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DashboardsDownloadBody") + + +@_attrs_define +class DashboardsDownloadBody: + """ + Attributes: + format_ (DashboardsDownloadBodyFormat): Output format for the download: pdf, png, csv, xlsx, or json Example: + pdf. + enable_formatting (bool | Unset): Compatible with csv, xlsx & json formats. If true, formatting will be enabled + in the output. Note: If true for json format, a queryIdentifierMapKey is required. Default: False. + expand_tables_to_show_all_rows (bool | Unset): Compatible with pdf and png formats. If true, up to 1,000 rows in + table visualizations will be included in the delivery. Note: This parameter cannot be used when paperFormat: + fit_page. + filter_config (Any | Unset): An object specifying the filter conditions to apply to the task. The filter key + specified must already exist in the dashboard. Example: {'status': ['active', 'pending']}. + hide_hidden_fields (bool | Unset): Compatible with csv & xlsx formats. If true, fields marked as hidden won't be + displayed in the output. Default: False. + hide_title (bool | Unset): Compatible with pdf & png formats. If true, the content's title will be hidden in the + output. Default: False. + max_row_limit (float | Unset): Compatible with csv, json, & xlsx formats. Used with overrideRowLimit. Specifies + the maximum number of rows. Example: 1000. + override_row_limit (bool | Unset): Compatible with csv, json, & xlsx formats. If true, the default row limit + will be overridden. Note: If true for json and xlsx formats, a queryIdentifierMapKey is required. Default: + False. + paper_format (DashboardsDownloadBodyPaperFormat | Unset): Compatible with pdf formats. Defines the paper format + (size) of the resulting PDF. Must be one of: a3, a4, letter, legal, fit_page, tabloid. Example: letter. + paper_orientation (DashboardsDownloadBodyPaperOrientation | Unset): Compatible with pdf formats. Defines the + paper orientation of the resulting PDF. Must be one of: portrait, landscape. Example: landscape. + query_identifier_map_key (str | Unset): Required for single tile tasks. The ID of the query to include in a + single tile task. Must reference a valid query in the dashboard. Example: Jmn2r3KV. + show_content_link (bool | Unset): Compatible with all formats except link_only. If true, a link to the content + will be shown in the output. Default: True. Example: True. + show_filters (bool | Unset): Compatible with all formats except link_only & csv. If true, filters will be shown + in the output. Default: True. Example: True. + single_column_layout (bool | Unset): Compatible with pdf and png formats. If true, dashboard tiles will be + arranged into a single vertical column. + use_cache (bool | Unset): If true, allow scheduled queries to use cached results instead of always running fresh + queries. Default: False. + filename (str | Unset): Custom filename for the downloaded file (without extension) Example: monthly-report. + """ + + format_: DashboardsDownloadBodyFormat + enable_formatting: bool | Unset = False + expand_tables_to_show_all_rows: bool | Unset = UNSET + filter_config: Any | Unset = UNSET + hide_hidden_fields: bool | Unset = False + hide_title: bool | Unset = False + max_row_limit: float | Unset = UNSET + override_row_limit: bool | Unset = False + paper_format: DashboardsDownloadBodyPaperFormat | Unset = UNSET + paper_orientation: DashboardsDownloadBodyPaperOrientation | Unset = UNSET + query_identifier_map_key: str | Unset = UNSET + show_content_link: bool | Unset = True + show_filters: bool | Unset = True + single_column_layout: bool | Unset = UNSET + use_cache: bool | Unset = False + filename: str | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + format_: str = self.format_ + + enable_formatting = self.enable_formatting + + expand_tables_to_show_all_rows = self.expand_tables_to_show_all_rows + + filter_config = self.filter_config + + hide_hidden_fields = self.hide_hidden_fields + + hide_title = self.hide_title + + max_row_limit = self.max_row_limit + + override_row_limit = self.override_row_limit + + paper_format: str | Unset = UNSET + if not isinstance(self.paper_format, Unset): + paper_format = self.paper_format + + paper_orientation: str | Unset = UNSET + if not isinstance(self.paper_orientation, Unset): + paper_orientation = self.paper_orientation + + query_identifier_map_key = self.query_identifier_map_key + + show_content_link = self.show_content_link + + show_filters = self.show_filters + + single_column_layout = self.single_column_layout + + use_cache = self.use_cache + + filename = self.filename + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "format": format_, + } + ) + if enable_formatting is not UNSET: + field_dict["enableFormatting"] = enable_formatting + if expand_tables_to_show_all_rows is not UNSET: + field_dict["expandTablesToShowAllRows"] = expand_tables_to_show_all_rows + if filter_config is not UNSET: + field_dict["filterConfig"] = filter_config + if hide_hidden_fields is not UNSET: + field_dict["hideHiddenFields"] = hide_hidden_fields + if hide_title is not UNSET: + field_dict["hideTitle"] = hide_title + if max_row_limit is not UNSET: + field_dict["maxRowLimit"] = max_row_limit + if override_row_limit is not UNSET: + field_dict["overrideRowLimit"] = override_row_limit + if paper_format is not UNSET: + field_dict["paperFormat"] = paper_format + if paper_orientation is not UNSET: + field_dict["paperOrientation"] = paper_orientation + if query_identifier_map_key is not UNSET: + field_dict["queryIdentifierMapKey"] = query_identifier_map_key + if show_content_link is not UNSET: + field_dict["showContentLink"] = show_content_link + if show_filters is not UNSET: + field_dict["showFilters"] = show_filters + if single_column_layout is not UNSET: + field_dict["singleColumnLayout"] = single_column_layout + if use_cache is not UNSET: + field_dict["useCache"] = use_cache + if filename is not UNSET: + field_dict["filename"] = filename + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + format_ = check_dashboards_download_body_format(d.pop("format")) + + enable_formatting = d.pop("enableFormatting", UNSET) + + expand_tables_to_show_all_rows = d.pop("expandTablesToShowAllRows", UNSET) + + filter_config = d.pop("filterConfig", UNSET) + + hide_hidden_fields = d.pop("hideHiddenFields", UNSET) + + hide_title = d.pop("hideTitle", UNSET) + + max_row_limit = d.pop("maxRowLimit", UNSET) + + override_row_limit = d.pop("overrideRowLimit", UNSET) + + _paper_format = d.pop("paperFormat", UNSET) + paper_format: DashboardsDownloadBodyPaperFormat | Unset + if isinstance(_paper_format, Unset): + paper_format = UNSET + else: + paper_format = check_dashboards_download_body_paper_format(_paper_format) + + _paper_orientation = d.pop("paperOrientation", UNSET) + paper_orientation: DashboardsDownloadBodyPaperOrientation | Unset + if isinstance(_paper_orientation, Unset): + paper_orientation = UNSET + else: + paper_orientation = check_dashboards_download_body_paper_orientation(_paper_orientation) + + query_identifier_map_key = d.pop("queryIdentifierMapKey", UNSET) + + show_content_link = d.pop("showContentLink", UNSET) + + show_filters = d.pop("showFilters", UNSET) + + single_column_layout = d.pop("singleColumnLayout", UNSET) + + use_cache = d.pop("useCache", UNSET) + + filename = d.pop("filename", UNSET) + + dashboards_download_body = cls( + format_=format_, + enable_formatting=enable_formatting, + expand_tables_to_show_all_rows=expand_tables_to_show_all_rows, + filter_config=filter_config, + hide_hidden_fields=hide_hidden_fields, + hide_title=hide_title, + max_row_limit=max_row_limit, + override_row_limit=override_row_limit, + paper_format=paper_format, + paper_orientation=paper_orientation, + query_identifier_map_key=query_identifier_map_key, + show_content_link=show_content_link, + show_filters=show_filters, + single_column_layout=single_column_layout, + use_cache=use_cache, + filename=filename, + ) + + return dashboards_download_body diff --git a/omni_python_sdk/models/dashboards_download_body_format.py b/omni_python_sdk/models/dashboards_download_body_format.py new file mode 100644 index 0000000..beaf164 --- /dev/null +++ b/omni_python_sdk/models/dashboards_download_body_format.py @@ -0,0 +1,17 @@ +from typing import Literal + +DashboardsDownloadBodyFormat = Literal["csv", "json", "pdf", "png", "xlsx"] + +DASHBOARDS_DOWNLOAD_BODY_FORMAT_VALUES: set[DashboardsDownloadBodyFormat] = { + "csv", + "json", + "pdf", + "png", + "xlsx", +} + + +def check_dashboards_download_body_format(value: str) -> DashboardsDownloadBodyFormat: + if value in DASHBOARDS_DOWNLOAD_BODY_FORMAT_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DASHBOARDS_DOWNLOAD_BODY_FORMAT_VALUES!r}") diff --git a/omni_python_sdk/models/dashboards_download_body_paper_format.py b/omni_python_sdk/models/dashboards_download_body_paper_format.py new file mode 100644 index 0000000..bc56a6a --- /dev/null +++ b/omni_python_sdk/models/dashboards_download_body_paper_format.py @@ -0,0 +1,18 @@ +from typing import Literal + +DashboardsDownloadBodyPaperFormat = Literal["a3", "a4", "fit_page", "legal", "letter", "tabloid"] + +DASHBOARDS_DOWNLOAD_BODY_PAPER_FORMAT_VALUES: set[DashboardsDownloadBodyPaperFormat] = { + "a3", + "a4", + "fit_page", + "legal", + "letter", + "tabloid", +} + + +def check_dashboards_download_body_paper_format(value: str) -> DashboardsDownloadBodyPaperFormat: + if value in DASHBOARDS_DOWNLOAD_BODY_PAPER_FORMAT_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DASHBOARDS_DOWNLOAD_BODY_PAPER_FORMAT_VALUES!r}") diff --git a/omni_python_sdk/models/dashboards_download_body_paper_orientation.py b/omni_python_sdk/models/dashboards_download_body_paper_orientation.py new file mode 100644 index 0000000..00e6a39 --- /dev/null +++ b/omni_python_sdk/models/dashboards_download_body_paper_orientation.py @@ -0,0 +1,16 @@ +from typing import Literal + +DashboardsDownloadBodyPaperOrientation = Literal["landscape", "portrait"] + +DASHBOARDS_DOWNLOAD_BODY_PAPER_ORIENTATION_VALUES: set[DashboardsDownloadBodyPaperOrientation] = { + "landscape", + "portrait", +} + + +def check_dashboards_download_body_paper_orientation(value: str) -> DashboardsDownloadBodyPaperOrientation: + if value in DASHBOARDS_DOWNLOAD_BODY_PAPER_ORIENTATION_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {DASHBOARDS_DOWNLOAD_BODY_PAPER_ORIENTATION_VALUES!r}" + ) diff --git a/omni_python_sdk/models/dashboards_download_response.py b/omni_python_sdk/models/dashboards_download_response.py new file mode 100644 index 0000000..2c844bc --- /dev/null +++ b/omni_python_sdk/models/dashboards_download_response.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DashboardsDownloadResponse") + + +@_attrs_define +class DashboardsDownloadResponse: + """ + Attributes: + job_id (UUID): ID of the download job. Use this to poll for download status. Example: + 123e4567-e89b-12d3-a456-426614174000. + message (str): Status message Example: Download initiated successfully. + """ + + job_id: UUID + message: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + job_id = str(self.job_id) + + message = self.message + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "job_id": job_id, + "message": message, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + job_id = UUID(d.pop("job_id")) + + message = d.pop("message") + + dashboards_download_response = cls( + job_id=job_id, + message=message, + ) + + dashboards_download_response.additional_properties = d + return dashboards_download_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dashboards_update_filters_body.py b/omni_python_sdk/models/dashboards_update_filters_body.py new file mode 100644 index 0000000..7ee6285 --- /dev/null +++ b/omni_python_sdk/models/dashboards_update_filters_body.py @@ -0,0 +1,115 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.dashboards_update_filters_body_controls import DashboardsUpdateFiltersBodyControls + from ..models.dashboards_update_filters_body_filters import DashboardsUpdateFiltersBodyFilters + + +T = TypeVar("T", bound="DashboardsUpdateFiltersBody") + + +@_attrs_define +class DashboardsUpdateFiltersBody: + """ + Attributes: + clear_existing_draft (bool | Unset): When true, discards any existing draft before applying updates. Required + when updating a published document that already has a draft. Default: False. + controls (DashboardsUpdateFiltersBodyControls | Unset): Partial control updates. Keys are control IDs that must + exist in the dashboard. + filter_order (list[str] | Unset): New order for filters. All filter IDs must exist in the dashboard. + filters (DashboardsUpdateFiltersBodyFilters | Unset): Partial filter updates. Keys are filter IDs that must + exist in the dashboard. + """ + + clear_existing_draft: bool | Unset = False + controls: DashboardsUpdateFiltersBodyControls | Unset = UNSET + filter_order: list[str] | Unset = UNSET + filters: DashboardsUpdateFiltersBodyFilters | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + clear_existing_draft = self.clear_existing_draft + + controls: dict[str, Any] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls.to_dict() + + filter_order: list[str] | Unset = UNSET + if not isinstance(self.filter_order, Unset): + filter_order = self.filter_order + + filters: dict[str, Any] | Unset = UNSET + if not isinstance(self.filters, Unset): + filters = self.filters.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if clear_existing_draft is not UNSET: + field_dict["clearExistingDraft"] = clear_existing_draft + if controls is not UNSET: + field_dict["controls"] = controls + if filter_order is not UNSET: + field_dict["filterOrder"] = filter_order + if filters is not UNSET: + field_dict["filters"] = filters + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.dashboards_update_filters_body_controls import DashboardsUpdateFiltersBodyControls + from ..models.dashboards_update_filters_body_filters import DashboardsUpdateFiltersBodyFilters + + d = dict(src_dict) + clear_existing_draft = d.pop("clearExistingDraft", UNSET) + + _controls = d.pop("controls", UNSET) + controls: DashboardsUpdateFiltersBodyControls | Unset + if isinstance(_controls, Unset): + controls = UNSET + else: + controls = DashboardsUpdateFiltersBodyControls.from_dict(_controls) + + filter_order = cast(list[str], d.pop("filterOrder", UNSET)) + + _filters = d.pop("filters", UNSET) + filters: DashboardsUpdateFiltersBodyFilters | Unset + if isinstance(_filters, Unset): + filters = UNSET + else: + filters = DashboardsUpdateFiltersBodyFilters.from_dict(_filters) + + dashboards_update_filters_body = cls( + clear_existing_draft=clear_existing_draft, + controls=controls, + filter_order=filter_order, + filters=filters, + ) + + dashboards_update_filters_body.additional_properties = d + return dashboards_update_filters_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dashboards_update_filters_body_controls.py b/omni_python_sdk/models/dashboards_update_filters_body_controls.py new file mode 100644 index 0000000..42488b5 --- /dev/null +++ b/omni_python_sdk/models/dashboards_update_filters_body_controls.py @@ -0,0 +1,66 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.dashboards_update_filters_body_controls_additional_property import ( + DashboardsUpdateFiltersBodyControlsAdditionalProperty, + ) + + +T = TypeVar("T", bound="DashboardsUpdateFiltersBodyControls") + + +@_attrs_define +class DashboardsUpdateFiltersBodyControls: + """Partial control updates. Keys are control IDs that must exist in the dashboard.""" + + additional_properties: dict[str, DashboardsUpdateFiltersBodyControlsAdditionalProperty] = _attrs_field( + init=False, factory=dict + ) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop.to_dict() + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.dashboards_update_filters_body_controls_additional_property import ( + DashboardsUpdateFiltersBodyControlsAdditionalProperty, + ) + + d = dict(src_dict) + dashboards_update_filters_body_controls = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + additional_property = DashboardsUpdateFiltersBodyControlsAdditionalProperty.from_dict(prop_dict) + + additional_properties[prop_name] = additional_property + + dashboards_update_filters_body_controls.additional_properties = additional_properties + return dashboards_update_filters_body_controls + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> DashboardsUpdateFiltersBodyControlsAdditionalProperty: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: DashboardsUpdateFiltersBodyControlsAdditionalProperty) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dashboards_update_filters_body_controls_additional_property.py b/omni_python_sdk/models/dashboards_update_filters_body_controls_additional_property.py new file mode 100644 index 0000000..504196f --- /dev/null +++ b/omni_python_sdk/models/dashboards_update_filters_body_controls_additional_property.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DashboardsUpdateFiltersBodyControlsAdditionalProperty") + + +@_attrs_define +class DashboardsUpdateFiltersBodyControlsAdditionalProperty: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + dashboards_update_filters_body_controls_additional_property = cls() + + dashboards_update_filters_body_controls_additional_property.additional_properties = d + return dashboards_update_filters_body_controls_additional_property + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dashboards_update_filters_body_filters.py b/omni_python_sdk/models/dashboards_update_filters_body_filters.py new file mode 100644 index 0000000..d7fe3f0 --- /dev/null +++ b/omni_python_sdk/models/dashboards_update_filters_body_filters.py @@ -0,0 +1,66 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.dashboards_update_filters_body_filters_additional_property import ( + DashboardsUpdateFiltersBodyFiltersAdditionalProperty, + ) + + +T = TypeVar("T", bound="DashboardsUpdateFiltersBodyFilters") + + +@_attrs_define +class DashboardsUpdateFiltersBodyFilters: + """Partial filter updates. Keys are filter IDs that must exist in the dashboard.""" + + additional_properties: dict[str, DashboardsUpdateFiltersBodyFiltersAdditionalProperty] = _attrs_field( + init=False, factory=dict + ) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop.to_dict() + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.dashboards_update_filters_body_filters_additional_property import ( + DashboardsUpdateFiltersBodyFiltersAdditionalProperty, + ) + + d = dict(src_dict) + dashboards_update_filters_body_filters = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + additional_property = DashboardsUpdateFiltersBodyFiltersAdditionalProperty.from_dict(prop_dict) + + additional_properties[prop_name] = additional_property + + dashboards_update_filters_body_filters.additional_properties = additional_properties + return dashboards_update_filters_body_filters + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> DashboardsUpdateFiltersBodyFiltersAdditionalProperty: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: DashboardsUpdateFiltersBodyFiltersAdditionalProperty) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dashboards_update_filters_body_filters_additional_property.py b/omni_python_sdk/models/dashboards_update_filters_body_filters_additional_property.py new file mode 100644 index 0000000..f1e5cdc --- /dev/null +++ b/omni_python_sdk/models/dashboards_update_filters_body_filters_additional_property.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DashboardsUpdateFiltersBodyFiltersAdditionalProperty") + + +@_attrs_define +class DashboardsUpdateFiltersBodyFiltersAdditionalProperty: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + dashboards_update_filters_body_filters_additional_property = cls() + + dashboards_update_filters_body_filters_additional_property.additional_properties = d + return dashboards_update_filters_body_filters_additional_property + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dbt_environment_create_body.py b/omni_python_sdk/models/dbt_environment_create_body.py new file mode 100644 index 0000000..92d5e57 --- /dev/null +++ b/omni_python_sdk/models/dbt_environment_create_body.py @@ -0,0 +1,189 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.dbt_environment_variable import DbtEnvironmentVariable + + +T = TypeVar("T", bound="DbtEnvironmentCreateBody") + + +@_attrs_define +class DbtEnvironmentCreateBody: + """ + Attributes: + name (str): Environment name Example: PR_1111_Expose. + target_schema (str): Target schema for this environment Example: PR_1111_Expose. + is_deferral_enabled (bool | Unset): Whether to enable dbt deferral for this environment. Ignored (forced to + false) for the default (production) environment. Default: False. + owner_id (None | str | Unset): User ID of the environment owner. Used to mark development environments belonging + to a specific user. + target_database (None | str | Unset): Target database override Example: analytics_dev. + target_name (None | str | Unset): Target name override + target_role (None | str | Unset): Target role override + variables (list[DbtEnvironmentVariable] | Unset): Environment variables + """ + + name: str + target_schema: str + is_deferral_enabled: bool | Unset = False + owner_id: None | str | Unset = UNSET + target_database: None | str | Unset = UNSET + target_name: None | str | Unset = UNSET + target_role: None | str | Unset = UNSET + variables: list[DbtEnvironmentVariable] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + target_schema = self.target_schema + + is_deferral_enabled = self.is_deferral_enabled + + owner_id: None | str | Unset + if isinstance(self.owner_id, Unset): + owner_id = UNSET + else: + owner_id = self.owner_id + + target_database: None | str | Unset + if isinstance(self.target_database, Unset): + target_database = UNSET + else: + target_database = self.target_database + + target_name: None | str | Unset + if isinstance(self.target_name, Unset): + target_name = UNSET + else: + target_name = self.target_name + + target_role: None | str | Unset + if isinstance(self.target_role, Unset): + target_role = UNSET + else: + target_role = self.target_role + + variables: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.variables, Unset): + variables = [] + for variables_item_data in self.variables: + variables_item = variables_item_data.to_dict() + variables.append(variables_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "targetSchema": target_schema, + } + ) + if is_deferral_enabled is not UNSET: + field_dict["isDeferralEnabled"] = is_deferral_enabled + if owner_id is not UNSET: + field_dict["ownerId"] = owner_id + if target_database is not UNSET: + field_dict["targetDatabase"] = target_database + if target_name is not UNSET: + field_dict["targetName"] = target_name + if target_role is not UNSET: + field_dict["targetRole"] = target_role + if variables is not UNSET: + field_dict["variables"] = variables + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.dbt_environment_variable import DbtEnvironmentVariable + + d = dict(src_dict) + name = d.pop("name") + + target_schema = d.pop("targetSchema") + + is_deferral_enabled = d.pop("isDeferralEnabled", UNSET) + + def _parse_owner_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + owner_id = _parse_owner_id(d.pop("ownerId", UNSET)) + + def _parse_target_database(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + target_database = _parse_target_database(d.pop("targetDatabase", UNSET)) + + def _parse_target_name(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + target_name = _parse_target_name(d.pop("targetName", UNSET)) + + def _parse_target_role(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + target_role = _parse_target_role(d.pop("targetRole", UNSET)) + + _variables = d.pop("variables", UNSET) + variables: list[DbtEnvironmentVariable] | Unset = UNSET + if _variables is not UNSET: + variables = [] + for variables_item_data in _variables: + variables_item = DbtEnvironmentVariable.from_dict(variables_item_data) + + variables.append(variables_item) + + dbt_environment_create_body = cls( + name=name, + target_schema=target_schema, + is_deferral_enabled=is_deferral_enabled, + owner_id=owner_id, + target_database=target_database, + target_name=target_name, + target_role=target_role, + variables=variables, + ) + + dbt_environment_create_body.additional_properties = d + return dbt_environment_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dbt_environment_delete_response.py b/omni_python_sdk/models/dbt_environment_delete_response.py new file mode 100644 index 0000000..9e50ed4 --- /dev/null +++ b/omni_python_sdk/models/dbt_environment_delete_response.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DbtEnvironmentDeleteResponse") + + +@_attrs_define +class DbtEnvironmentDeleteResponse: + """ + Attributes: + message (str): Confirmation message Example: dbt environment deleted successfully. + success (bool): Whether the deletion was successful Example: True. + """ + + message: str + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + success = d.pop("success") + + dbt_environment_delete_response = cls( + message=message, + success=success, + ) + + dbt_environment_delete_response.additional_properties = d + return dbt_environment_delete_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dbt_environment_item.py b/omni_python_sdk/models/dbt_environment_item.py new file mode 100644 index 0000000..4bb238d --- /dev/null +++ b/omni_python_sdk/models/dbt_environment_item.py @@ -0,0 +1,173 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.dbt_environment_response_variable import DbtEnvironmentResponseVariable + + +T = TypeVar("T", bound="DbtEnvironmentItem") + + +@_attrs_define +class DbtEnvironmentItem: + """ + Attributes: + id (UUID): Unique environment identifier + is_default_environment (bool): Whether this is the default environment + is_deferral_enabled (bool): Whether dbt deferral is enabled for this environment. Always false for the default + (production) environment — the backend rejects enabling it there. + name (str): Environment name + owner_id (None | str): User ID of the environment owner, or null if not a personal environment + target_database (None | str): Target database override + target_name (None | str): Target name override + target_role (None | str): Target role override + target_schema (str): Target schema + variables (list[DbtEnvironmentResponseVariable]): Environment variables + """ + + id: UUID + is_default_environment: bool + is_deferral_enabled: bool + name: str + owner_id: None | str + target_database: None | str + target_name: None | str + target_role: None | str + target_schema: str + variables: list[DbtEnvironmentResponseVariable] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + is_default_environment = self.is_default_environment + + is_deferral_enabled = self.is_deferral_enabled + + name = self.name + + owner_id: None | str + owner_id = self.owner_id + + target_database: None | str + target_database = self.target_database + + target_name: None | str + target_name = self.target_name + + target_role: None | str + target_role = self.target_role + + target_schema = self.target_schema + + variables = [] + for variables_item_data in self.variables: + variables_item = variables_item_data.to_dict() + variables.append(variables_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "isDefaultEnvironment": is_default_environment, + "isDeferralEnabled": is_deferral_enabled, + "name": name, + "ownerId": owner_id, + "targetDatabase": target_database, + "targetName": target_name, + "targetRole": target_role, + "targetSchema": target_schema, + "variables": variables, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.dbt_environment_response_variable import DbtEnvironmentResponseVariable + + d = dict(src_dict) + id = UUID(d.pop("id")) + + is_default_environment = d.pop("isDefaultEnvironment") + + is_deferral_enabled = d.pop("isDeferralEnabled") + + name = d.pop("name") + + def _parse_owner_id(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + owner_id = _parse_owner_id(d.pop("ownerId")) + + def _parse_target_database(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + target_database = _parse_target_database(d.pop("targetDatabase")) + + def _parse_target_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + target_name = _parse_target_name(d.pop("targetName")) + + def _parse_target_role(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + target_role = _parse_target_role(d.pop("targetRole")) + + target_schema = d.pop("targetSchema") + + variables = [] + _variables = d.pop("variables") + for variables_item_data in _variables: + variables_item = DbtEnvironmentResponseVariable.from_dict(variables_item_data) + + variables.append(variables_item) + + dbt_environment_item = cls( + id=id, + is_default_environment=is_default_environment, + is_deferral_enabled=is_deferral_enabled, + name=name, + owner_id=owner_id, + target_database=target_database, + target_name=target_name, + target_role=target_role, + target_schema=target_schema, + variables=variables, + ) + + dbt_environment_item.additional_properties = d + return dbt_environment_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dbt_environment_list_response.py b/omni_python_sdk/models/dbt_environment_list_response.py new file mode 100644 index 0000000..cd74938 --- /dev/null +++ b/omni_python_sdk/models/dbt_environment_list_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.dbt_environment_item import DbtEnvironmentItem + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="DbtEnvironmentListResponse") + + +@_attrs_define +class DbtEnvironmentListResponse: + """ + Attributes: + page_info (PageInfo): + records (list[DbtEnvironmentItem]): + """ + + page_info: PageInfo + records: list[DbtEnvironmentItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.dbt_environment_item import DbtEnvironmentItem + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = DbtEnvironmentItem.from_dict(records_item_data) + + records.append(records_item) + + dbt_environment_list_response = cls( + page_info=page_info, + records=records, + ) + + dbt_environment_list_response.additional_properties = d + return dbt_environment_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dbt_environment_response_variable.py b/omni_python_sdk/models/dbt_environment_response_variable.py new file mode 100644 index 0000000..a6487f8 --- /dev/null +++ b/omni_python_sdk/models/dbt_environment_response_variable.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DbtEnvironmentResponseVariable") + + +@_attrs_define +class DbtEnvironmentResponseVariable: + """ + Attributes: + id (UUID): Variable ID + is_secret (bool): Whether the variable value is secret + name (str): Variable name + value (None | str): Variable value (null for secret variables) + """ + + id: UUID + is_secret: bool + name: str + value: None | str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + is_secret = self.is_secret + + name = self.name + + value: None | str + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "isSecret": is_secret, + "name": name, + "value": value, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = UUID(d.pop("id")) + + is_secret = d.pop("isSecret") + + name = d.pop("name") + + def _parse_value(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + value = _parse_value(d.pop("value")) + + dbt_environment_response_variable = cls( + id=id, + is_secret=is_secret, + name=name, + value=value, + ) + + dbt_environment_response_variable.additional_properties = d + return dbt_environment_response_variable + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dbt_environment_update_body.py b/omni_python_sdk/models/dbt_environment_update_body.py new file mode 100644 index 0000000..3040900 --- /dev/null +++ b/omni_python_sdk/models/dbt_environment_update_body.py @@ -0,0 +1,219 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.dbt_environment_variable import DbtEnvironmentVariable + from ..models.dbt_environment_variable_update import DbtEnvironmentVariableUpdate + + +T = TypeVar("T", bound="DbtEnvironmentUpdateBody") + + +@_attrs_define +class DbtEnvironmentUpdateBody: + """ + Attributes: + name (str): Environment name Example: PR_1111_Expose. + target_schema (str): Target schema for this environment Example: PR_1111_Expose. + is_deferral_enabled (bool | Unset): Whether to enable dbt deferral for this environment. Ignored (forced to + false) for the default (production) environment. Default: False. + owner_id (None | str | Unset): User ID of the environment owner. Used to mark development environments belonging + to a specific user. + target_database (None | str | Unset): Target database override Example: analytics_dev. + target_name (None | str | Unset): Target name override + target_role (None | str | Unset): Target role override + variables (list[DbtEnvironmentVariable | DbtEnvironmentVariableUpdate] | Unset): Environment variables. + Variables with an id update existing ones; variables without an id create new ones. + """ + + name: str + target_schema: str + is_deferral_enabled: bool | Unset = False + owner_id: None | str | Unset = UNSET + target_database: None | str | Unset = UNSET + target_name: None | str | Unset = UNSET + target_role: None | str | Unset = UNSET + variables: list[DbtEnvironmentVariable | DbtEnvironmentVariableUpdate] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.dbt_environment_variable_update import DbtEnvironmentVariableUpdate + + name = self.name + + target_schema = self.target_schema + + is_deferral_enabled = self.is_deferral_enabled + + owner_id: None | str | Unset + if isinstance(self.owner_id, Unset): + owner_id = UNSET + else: + owner_id = self.owner_id + + target_database: None | str | Unset + if isinstance(self.target_database, Unset): + target_database = UNSET + else: + target_database = self.target_database + + target_name: None | str | Unset + if isinstance(self.target_name, Unset): + target_name = UNSET + else: + target_name = self.target_name + + target_role: None | str | Unset + if isinstance(self.target_role, Unset): + target_role = UNSET + else: + target_role = self.target_role + + variables: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.variables, Unset): + variables = [] + for variables_item_data in self.variables: + variables_item: dict[str, Any] + if isinstance(variables_item_data, DbtEnvironmentVariableUpdate): + variables_item = variables_item_data.to_dict() + else: + variables_item = variables_item_data.to_dict() + + variables.append(variables_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "targetSchema": target_schema, + } + ) + if is_deferral_enabled is not UNSET: + field_dict["isDeferralEnabled"] = is_deferral_enabled + if owner_id is not UNSET: + field_dict["ownerId"] = owner_id + if target_database is not UNSET: + field_dict["targetDatabase"] = target_database + if target_name is not UNSET: + field_dict["targetName"] = target_name + if target_role is not UNSET: + field_dict["targetRole"] = target_role + if variables is not UNSET: + field_dict["variables"] = variables + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.dbt_environment_variable import DbtEnvironmentVariable + from ..models.dbt_environment_variable_update import DbtEnvironmentVariableUpdate + + d = dict(src_dict) + name = d.pop("name") + + target_schema = d.pop("targetSchema") + + is_deferral_enabled = d.pop("isDeferralEnabled", UNSET) + + def _parse_owner_id(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + owner_id = _parse_owner_id(d.pop("ownerId", UNSET)) + + def _parse_target_database(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + target_database = _parse_target_database(d.pop("targetDatabase", UNSET)) + + def _parse_target_name(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + target_name = _parse_target_name(d.pop("targetName", UNSET)) + + def _parse_target_role(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + target_role = _parse_target_role(d.pop("targetRole", UNSET)) + + _variables = d.pop("variables", UNSET) + variables: list[DbtEnvironmentVariable | DbtEnvironmentVariableUpdate] | Unset = UNSET + if _variables is not UNSET: + variables = [] + for variables_item_data in _variables: + + def _parse_variables_item(data: object) -> DbtEnvironmentVariable | DbtEnvironmentVariableUpdate: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_dbt_environment_variable_update_or_new_type_0 = ( + DbtEnvironmentVariableUpdate.from_dict(data) + ) + + return componentsschemas_dbt_environment_variable_update_or_new_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_dbt_environment_variable_update_or_new_type_1 = DbtEnvironmentVariable.from_dict( + data + ) + + return componentsschemas_dbt_environment_variable_update_or_new_type_1 + + variables_item = _parse_variables_item(variables_item_data) + + variables.append(variables_item) + + dbt_environment_update_body = cls( + name=name, + target_schema=target_schema, + is_deferral_enabled=is_deferral_enabled, + owner_id=owner_id, + target_database=target_database, + target_name=target_name, + target_role=target_role, + variables=variables, + ) + + dbt_environment_update_body.additional_properties = d + return dbt_environment_update_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dbt_environment_variable.py b/omni_python_sdk/models/dbt_environment_variable.py new file mode 100644 index 0000000..3a2911a --- /dev/null +++ b/omni_python_sdk/models/dbt_environment_variable.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DbtEnvironmentVariable") + + +@_attrs_define +class DbtEnvironmentVariable: + """ + Attributes: + is_secret (bool): Whether the variable value is secret + name (str): Variable name + value (str): Variable value + """ + + is_secret: bool + name: str + value: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + is_secret = self.is_secret + + name = self.name + + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "isSecret": is_secret, + "name": name, + "value": value, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + is_secret = d.pop("isSecret") + + name = d.pop("name") + + value = d.pop("value") + + dbt_environment_variable = cls( + is_secret=is_secret, + name=name, + value=value, + ) + + dbt_environment_variable.additional_properties = d + return dbt_environment_variable + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dbt_environment_variable_update.py b/omni_python_sdk/models/dbt_environment_variable_update.py new file mode 100644 index 0000000..2c67d1c --- /dev/null +++ b/omni_python_sdk/models/dbt_environment_variable_update.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DbtEnvironmentVariableUpdate") + + +@_attrs_define +class DbtEnvironmentVariableUpdate: + """Update an existing variable by ID. Variable names cannot be changed after creation. + + Attributes: + id (UUID): Existing variable ID + is_secret (bool): Whether the variable value is secret + value (None | str | Unset): Updated variable value. Omit or set to null to keep the existing value for secret + variables. + """ + + id: UUID + is_secret: bool + value: None | str | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + is_secret = self.is_secret + + value: None | str | Unset + if isinstance(self.value, Unset): + value = UNSET + else: + value = self.value + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "id": id, + "isSecret": is_secret, + } + ) + if value is not UNSET: + field_dict["value"] = value + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = UUID(d.pop("id")) + + is_secret = d.pop("isSecret") + + def _parse_value(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + value = _parse_value(d.pop("value", UNSET)) + + dbt_environment_variable_update = cls( + id=id, + is_secret=is_secret, + value=value, + ) + + return dbt_environment_variable_update diff --git a/omni_python_sdk/models/dbt_exposure.py b/omni_python_sdk/models/dbt_exposure.py new file mode 100644 index 0000000..49f8cab --- /dev/null +++ b/omni_python_sdk/models/dbt_exposure.py @@ -0,0 +1,115 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.dbt_exposure_type import DbtExposureType, check_dbt_exposure_type +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.dbt_exposure_owner import DbtExposureOwner + + +T = TypeVar("T", bound="DbtExposure") + + +@_attrs_define +class DbtExposure: + """The dbt exposure for this dashboard. + + Attributes: + depends_on (list[str]): List of dbt model references (e.g. ref('model_name')) Example: ["ref('orders')", + "ref('customers')"]. + name (str): Sanitized exposure name. May contain duplicates across exposures; use deduplication_name for a + guaranteed-unique alternative. Example: my_dashboard. + owner (DbtExposureOwner): + type_ (DbtExposureType): Type of the exposure Example: dashboard. + label (str | Unset): Original dashboard name + url (str | Unset): URL of the dashboard + """ + + depends_on: list[str] + name: str + owner: DbtExposureOwner + type_: DbtExposureType + label: str | Unset = UNSET + url: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + depends_on = self.depends_on + + name = self.name + + owner = self.owner.to_dict() + + type_: str = self.type_ + + label = self.label + + url = self.url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "depends_on": depends_on, + "name": name, + "owner": owner, + "type": type_, + } + ) + if label is not UNSET: + field_dict["label"] = label + if url is not UNSET: + field_dict["url"] = url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.dbt_exposure_owner import DbtExposureOwner + + d = dict(src_dict) + depends_on = cast(list[str], d.pop("depends_on")) + + name = d.pop("name") + + owner = DbtExposureOwner.from_dict(d.pop("owner")) + + type_ = check_dbt_exposure_type(d.pop("type")) + + label = d.pop("label", UNSET) + + url = d.pop("url", UNSET) + + dbt_exposure = cls( + depends_on=depends_on, + name=name, + owner=owner, + type_=type_, + label=label, + url=url, + ) + + dbt_exposure.additional_properties = d + return dbt_exposure + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dbt_exposure_owner.py b/omni_python_sdk/models/dbt_exposure_owner.py new file mode 100644 index 0000000..8e92be2 --- /dev/null +++ b/omni_python_sdk/models/dbt_exposure_owner.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DbtExposureOwner") + + +@_attrs_define +class DbtExposureOwner: + """ + Attributes: + email (str): Email of the dashboard owner + name (str): Name of the dashboard owner + """ + + email: str + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + email = self.email + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "email": email, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + email = d.pop("email") + + name = d.pop("name") + + dbt_exposure_owner = cls( + email=email, + name=name, + ) + + dbt_exposure_owner.additional_properties = d + return dbt_exposure_owner + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/dbt_exposure_type.py b/omni_python_sdk/models/dbt_exposure_type.py new file mode 100644 index 0000000..8859113 --- /dev/null +++ b/omni_python_sdk/models/dbt_exposure_type.py @@ -0,0 +1,17 @@ +from typing import Literal + +DbtExposureType = Literal["analysis", "application", "dashboard", "ml", "notebook"] + +DBT_EXPOSURE_TYPE_VALUES: set[DbtExposureType] = { + "analysis", + "application", + "dashboard", + "ml", + "notebook", +} + + +def check_dbt_exposure_type(value: str) -> DbtExposureType: + if value in DBT_EXPOSURE_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DBT_EXPOSURE_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/dbt_exposure_with_meta.py b/omni_python_sdk/models/dbt_exposure_with_meta.py new file mode 100644 index 0000000..bcd4fc2 --- /dev/null +++ b/omni_python_sdk/models/dbt_exposure_with_meta.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.dbt_exposure import DbtExposure + + +T = TypeVar("T", bound="DbtExposureWithMeta") + + +@_attrs_define +class DbtExposureWithMeta: + """ + Attributes: + dashboard_identifier (str): Identifier of the dashboard that generated this exposure + deduplication_name (str): A unique name for this exposure. Use this instead of exposure.name to avoid duplicate + names, or use it as a fallback when exposure.name collides with another exposure. + exposure (DbtExposure): The dbt exposure for this dashboard. + """ + + dashboard_identifier: str + deduplication_name: str + exposure: DbtExposure + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + dashboard_identifier = self.dashboard_identifier + + deduplication_name = self.deduplication_name + + exposure = self.exposure.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "dashboard_identifier": dashboard_identifier, + "deduplication_name": deduplication_name, + "exposure": exposure, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.dbt_exposure import DbtExposure + + d = dict(src_dict) + dashboard_identifier = d.pop("dashboard_identifier") + + deduplication_name = d.pop("deduplication_name") + + exposure = DbtExposure.from_dict(d.pop("exposure")) + + dbt_exposure_with_meta = cls( + dashboard_identifier=dashboard_identifier, + deduplication_name=deduplication_name, + exposure=exposure, + ) + + dbt_exposure_with_meta.additional_properties = d + return dbt_exposure_with_meta + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document.py b/omni_python_sdk/models/document.py new file mode 100644 index 0000000..04bf0c1 --- /dev/null +++ b/omni_python_sdk/models/document.py @@ -0,0 +1,249 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.document_scope import DocumentScope, check_document_scope +from ..models.document_type import DocumentType, check_document_type +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.document_count import DocumentCount + from ..models.document_folder_type_0 import DocumentFolderType0 + from ..models.document_owner import DocumentOwner + + +T = TypeVar("T", bound="Document") + + +@_attrs_define +class Document: + """ + Attributes: + connection_id (str): Connection ID the document is associated with + deleted (bool): Whether the document is deleted (archived) + folder (DocumentFolderType0 | None): Folder containing the document + has_dashboard (bool): Whether the document has an associated dashboard + identifier (str): Document identifier Example: abc123. + name (str): Document name + owner (DocumentOwner): Document owner + scope (DocumentScope): Document access scope + type_ (DocumentType): Content type + updated_at (datetime.datetime | None): Last updated timestamp + url (str): URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an + app, otherwise the workbook URL. Example: https://org.omni.co/dashboards/abc123. + field_count (DocumentCount | Unset): Document counts (included when _count is in include param) + description (None | str | Unset): Document description + has_app (bool | Unset): Whether the document has an associated app + labels (list[str] | Unset): Labels applied to the document (included when labels is in include param) + """ + + connection_id: str + deleted: bool + folder: DocumentFolderType0 | None + has_dashboard: bool + identifier: str + name: str + owner: DocumentOwner + scope: DocumentScope + type_: DocumentType + updated_at: datetime.datetime | None + url: str + field_count: DocumentCount | Unset = UNSET + description: None | str | Unset = UNSET + has_app: bool | Unset = UNSET + labels: list[str] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.document_folder_type_0 import DocumentFolderType0 + + connection_id = self.connection_id + + deleted = self.deleted + + folder: dict[str, Any] | None + if isinstance(self.folder, DocumentFolderType0): + folder = self.folder.to_dict() + else: + folder = self.folder + + has_dashboard = self.has_dashboard + + identifier = self.identifier + + name = self.name + + owner = self.owner.to_dict() + + scope: str = self.scope + + type_: str = self.type_ + + updated_at: None | str + if isinstance(self.updated_at, datetime.datetime): + updated_at = self.updated_at.isoformat() + else: + updated_at = self.updated_at + + url = self.url + + field_count: dict[str, Any] | Unset = UNSET + if not isinstance(self.field_count, Unset): + field_count = self.field_count.to_dict() + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + has_app = self.has_app + + labels: list[str] | Unset = UNSET + if not isinstance(self.labels, Unset): + labels = self.labels + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "connectionId": connection_id, + "deleted": deleted, + "folder": folder, + "hasDashboard": has_dashboard, + "identifier": identifier, + "name": name, + "owner": owner, + "scope": scope, + "type": type_, + "updatedAt": updated_at, + "url": url, + } + ) + if field_count is not UNSET: + field_dict["_count"] = field_count + if description is not UNSET: + field_dict["description"] = description + if has_app is not UNSET: + field_dict["hasApp"] = has_app + if labels is not UNSET: + field_dict["labels"] = labels + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.document_count import DocumentCount + from ..models.document_folder_type_0 import DocumentFolderType0 + from ..models.document_owner import DocumentOwner + + d = dict(src_dict) + connection_id = d.pop("connectionId") + + deleted = d.pop("deleted") + + def _parse_folder(data: object) -> DocumentFolderType0 | None: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_document_folder_type_0 = DocumentFolderType0.from_dict(data) + + return componentsschemas_document_folder_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(DocumentFolderType0 | None, data) + + folder = _parse_folder(d.pop("folder")) + + has_dashboard = d.pop("hasDashboard") + + identifier = d.pop("identifier") + + name = d.pop("name") + + owner = DocumentOwner.from_dict(d.pop("owner")) + + scope = check_document_scope(d.pop("scope")) + + type_ = check_document_type(d.pop("type")) + + def _parse_updated_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + updated_at_type_0 = datetime.datetime.fromisoformat(data) + + return updated_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + updated_at = _parse_updated_at(d.pop("updatedAt")) + + url = d.pop("url") + + _field_count = d.pop("_count", UNSET) + field_count: DocumentCount | Unset + if isinstance(_field_count, Unset): + field_count = UNSET + else: + field_count = DocumentCount.from_dict(_field_count) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + has_app = d.pop("hasApp", UNSET) + + labels = cast(list[str], d.pop("labels", UNSET)) + + document = cls( + connection_id=connection_id, + deleted=deleted, + folder=folder, + has_dashboard=has_dashboard, + identifier=identifier, + name=name, + owner=owner, + scope=scope, + type_=type_, + updated_at=updated_at, + url=url, + field_count=field_count, + description=description, + has_app=has_app, + labels=labels, + ) + + document.additional_properties = d + return document + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_count.py b/omni_python_sdk/models/document_count.py new file mode 100644 index 0000000..7a5e4e5 --- /dev/null +++ b/omni_python_sdk/models/document_count.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentCount") + + +@_attrs_define +class DocumentCount: + """Document counts (included when _count is in include param) + + Attributes: + favorites (float): Number of users who favorited this document + views (float): Number of views + """ + + favorites: float + views: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + favorites = self.favorites + + views = self.views + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "favorites": favorites, + "views": views, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + favorites = d.pop("favorites") + + views = d.pop("views") + + document_count = cls( + favorites=favorites, + views=views, + ) + + document_count.additional_properties = d + return document_count + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_export_response.py b/omni_python_sdk/models/document_export_response.py new file mode 100644 index 0000000..ba31149 --- /dev/null +++ b/omni_python_sdk/models/document_export_response.py @@ -0,0 +1,123 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.document_export_response_document import DocumentExportResponseDocument + from ..models.document_export_response_file_uploads import DocumentExportResponseFileUploads + from ..models.document_export_response_query_models import DocumentExportResponseQueryModels + + +T = TypeVar("T", bound="DocumentExportResponse") + + +@_attrs_define +class DocumentExportResponse: + """ + Attributes: + document (DocumentExportResponseDocument): + export_version (str): + query_models (DocumentExportResponseQueryModels): + dashboard (Any | Unset): Dashboard configuration and layout + file_uploads (DocumentExportResponseFileUploads | Unset): + workbook_model (Any | Unset): + """ + + document: DocumentExportResponseDocument + export_version: str + query_models: DocumentExportResponseQueryModels + dashboard: Any | Unset = UNSET + file_uploads: DocumentExportResponseFileUploads | Unset = UNSET + workbook_model: Any | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + document = self.document.to_dict() + + export_version = self.export_version + + query_models = self.query_models.to_dict() + + dashboard = self.dashboard + + file_uploads: dict[str, Any] | Unset = UNSET + if not isinstance(self.file_uploads, Unset): + file_uploads = self.file_uploads.to_dict() + + workbook_model = self.workbook_model + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "document": document, + "exportVersion": export_version, + "queryModels": query_models, + } + ) + if dashboard is not UNSET: + field_dict["dashboard"] = dashboard + if file_uploads is not UNSET: + field_dict["fileUploads"] = file_uploads + if workbook_model is not UNSET: + field_dict["workbookModel"] = workbook_model + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.document_export_response_document import DocumentExportResponseDocument + from ..models.document_export_response_file_uploads import DocumentExportResponseFileUploads + from ..models.document_export_response_query_models import DocumentExportResponseQueryModels + + d = dict(src_dict) + document = DocumentExportResponseDocument.from_dict(d.pop("document")) + + export_version = d.pop("exportVersion") + + query_models = DocumentExportResponseQueryModels.from_dict(d.pop("queryModels")) + + dashboard = d.pop("dashboard", UNSET) + + _file_uploads = d.pop("fileUploads", UNSET) + file_uploads: DocumentExportResponseFileUploads | Unset + if isinstance(_file_uploads, Unset): + file_uploads = UNSET + else: + file_uploads = DocumentExportResponseFileUploads.from_dict(_file_uploads) + + workbook_model = d.pop("workbookModel", UNSET) + + document_export_response = cls( + document=document, + export_version=export_version, + query_models=query_models, + dashboard=dashboard, + file_uploads=file_uploads, + workbook_model=workbook_model, + ) + + document_export_response.additional_properties = d + return document_export_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_export_response_document.py b/omni_python_sdk/models/document_export_response_document.py new file mode 100644 index 0000000..f53563b --- /dev/null +++ b/omni_python_sdk/models/document_export_response_document.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentExportResponseDocument") + + +@_attrs_define +class DocumentExportResponseDocument: + """ + Attributes: + name (str): + ephemeral (str | Unset): + """ + + name: str + ephemeral: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + ephemeral = self.ephemeral + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + if ephemeral is not UNSET: + field_dict["ephemeral"] = ephemeral + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + name = d.pop("name") + + ephemeral = d.pop("ephemeral", UNSET) + + document_export_response_document = cls( + name=name, + ephemeral=ephemeral, + ) + + document_export_response_document.additional_properties = d + return document_export_response_document + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_export_response_file_uploads.py b/omni_python_sdk/models/document_export_response_file_uploads.py new file mode 100644 index 0000000..29bc799 --- /dev/null +++ b/omni_python_sdk/models/document_export_response_file_uploads.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentExportResponseFileUploads") + + +@_attrs_define +class DocumentExportResponseFileUploads: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + document_export_response_file_uploads = cls() + + document_export_response_file_uploads.additional_properties = d + return document_export_response_file_uploads + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_export_response_query_models.py b/omni_python_sdk/models/document_export_response_query_models.py new file mode 100644 index 0000000..0d4c447 --- /dev/null +++ b/omni_python_sdk/models/document_export_response_query_models.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentExportResponseQueryModels") + + +@_attrs_define +class DocumentExportResponseQueryModels: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + document_export_response_query_models = cls() + + document_export_response_query_models.additional_properties = d + return document_export_response_query_models + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_favorite_user.py b/omni_python_sdk/models/document_favorite_user.py new file mode 100644 index 0000000..abae355 --- /dev/null +++ b/omni_python_sdk/models/document_favorite_user.py @@ -0,0 +1,94 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentFavoriteUser") + + +@_attrs_define +class DocumentFavoriteUser: + """ + Attributes: + email (None | str): Favoriting user's email. Null when the user has no resolvable email — e.g. an embed-SSO + favoriter whose embed session did not provide one. + favorited_at (str): ISO 8601 timestamp when the user favorited the document + name (str): Favoriting user's display name + user_id (str): Membership ID of the user who favorited the document (use with other v1 endpoints' userId + parameter) + """ + + email: None | str + favorited_at: str + name: str + user_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + email: None | str + email = self.email + + favorited_at = self.favorited_at + + name = self.name + + user_id = self.user_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "email": email, + "favoritedAt": favorited_at, + "name": name, + "userId": user_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_email(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + email = _parse_email(d.pop("email")) + + favorited_at = d.pop("favoritedAt") + + name = d.pop("name") + + user_id = d.pop("userId") + + document_favorite_user = cls( + email=email, + favorited_at=favorited_at, + name=name, + user_id=user_id, + ) + + document_favorite_user.additional_properties = d + return document_favorite_user + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_folder_type_0.py b/omni_python_sdk/models/document_folder_type_0.py new file mode 100644 index 0000000..388659c --- /dev/null +++ b/omni_python_sdk/models/document_folder_type_0.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.document_folder_type_0_scope import DocumentFolderType0Scope, check_document_folder_type_0_scope + +T = TypeVar("T", bound="DocumentFolderType0") + + +@_attrs_define +class DocumentFolderType0: + """Folder containing the document + + Attributes: + id (str): Folder ID + name (str): Folder name + path (str): Folder path + scope (DocumentFolderType0Scope): Folder access scope + """ + + id: str + name: str + path: str + scope: DocumentFolderType0Scope + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + path = self.path + + scope: str = self.scope + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + "path": path, + "scope": scope, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + name = d.pop("name") + + path = d.pop("path") + + scope = check_document_folder_type_0_scope(d.pop("scope")) + + document_folder_type_0 = cls( + id=id, + name=name, + path=path, + scope=scope, + ) + + document_folder_type_0.additional_properties = d + return document_folder_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_folder_type_0_scope.py b/omni_python_sdk/models/document_folder_type_0_scope.py new file mode 100644 index 0000000..5613378 --- /dev/null +++ b/omni_python_sdk/models/document_folder_type_0_scope.py @@ -0,0 +1,14 @@ +from typing import Literal + +DocumentFolderType0Scope = Literal["organization", "restricted"] + +DOCUMENT_FOLDER_TYPE_0_SCOPE_VALUES: set[DocumentFolderType0Scope] = { + "organization", + "restricted", +} + + +def check_document_folder_type_0_scope(value: str) -> DocumentFolderType0Scope: + if value in DOCUMENT_FOLDER_TYPE_0_SCOPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENT_FOLDER_TYPE_0_SCOPE_VALUES!r}") diff --git a/omni_python_sdk/models/document_import_body.py b/omni_python_sdk/models/document_import_body.py new file mode 100644 index 0000000..72d0d6c --- /dev/null +++ b/omni_python_sdk/models/document_import_body.py @@ -0,0 +1,154 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.document_import_body_export_version import ( + DocumentImportBodyExportVersion, + check_document_import_body_export_version, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.document_import_body_document import DocumentImportBodyDocument + from ..models.document_import_body_file_uploads import DocumentImportBodyFileUploads + from ..models.document_import_body_query_models import DocumentImportBodyQueryModels + + +T = TypeVar("T", bound="DocumentImportBody") + + +@_attrs_define +class DocumentImportBody: + """ + Attributes: + base_model_id (UUID): Base model ID for the imported document + document (DocumentImportBodyDocument): + export_version (DocumentImportBodyExportVersion): + query_models (DocumentImportBodyQueryModels): + dashboard (Any | Unset): Dashboard export data + file_uploads (DocumentImportBodyFileUploads | Unset): + folder_path (str | Unset): + identifier (str | Unset): + workbook_model (Any | Unset): + """ + + base_model_id: UUID + document: DocumentImportBodyDocument + export_version: DocumentImportBodyExportVersion + query_models: DocumentImportBodyQueryModels + dashboard: Any | Unset = UNSET + file_uploads: DocumentImportBodyFileUploads | Unset = UNSET + folder_path: str | Unset = UNSET + identifier: str | Unset = UNSET + workbook_model: Any | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + base_model_id = str(self.base_model_id) + + document = self.document.to_dict() + + export_version: str = self.export_version + + query_models = self.query_models.to_dict() + + dashboard = self.dashboard + + file_uploads: dict[str, Any] | Unset = UNSET + if not isinstance(self.file_uploads, Unset): + file_uploads = self.file_uploads.to_dict() + + folder_path = self.folder_path + + identifier = self.identifier + + workbook_model = self.workbook_model + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "baseModelId": base_model_id, + "document": document, + "exportVersion": export_version, + "queryModels": query_models, + } + ) + if dashboard is not UNSET: + field_dict["dashboard"] = dashboard + if file_uploads is not UNSET: + field_dict["fileUploads"] = file_uploads + if folder_path is not UNSET: + field_dict["folderPath"] = folder_path + if identifier is not UNSET: + field_dict["identifier"] = identifier + if workbook_model is not UNSET: + field_dict["workbookModel"] = workbook_model + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.document_import_body_document import DocumentImportBodyDocument + from ..models.document_import_body_file_uploads import DocumentImportBodyFileUploads + from ..models.document_import_body_query_models import DocumentImportBodyQueryModels + + d = dict(src_dict) + base_model_id = UUID(d.pop("baseModelId")) + + document = DocumentImportBodyDocument.from_dict(d.pop("document")) + + export_version = check_document_import_body_export_version(d.pop("exportVersion")) + + query_models = DocumentImportBodyQueryModels.from_dict(d.pop("queryModels")) + + dashboard = d.pop("dashboard", UNSET) + + _file_uploads = d.pop("fileUploads", UNSET) + file_uploads: DocumentImportBodyFileUploads | Unset + if isinstance(_file_uploads, Unset): + file_uploads = UNSET + else: + file_uploads = DocumentImportBodyFileUploads.from_dict(_file_uploads) + + folder_path = d.pop("folderPath", UNSET) + + identifier = d.pop("identifier", UNSET) + + workbook_model = d.pop("workbookModel", UNSET) + + document_import_body = cls( + base_model_id=base_model_id, + document=document, + export_version=export_version, + query_models=query_models, + dashboard=dashboard, + file_uploads=file_uploads, + folder_path=folder_path, + identifier=identifier, + workbook_model=workbook_model, + ) + + document_import_body.additional_properties = d + return document_import_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_import_body_document.py b/omni_python_sdk/models/document_import_body_document.py new file mode 100644 index 0000000..d4da1d9 --- /dev/null +++ b/omni_python_sdk/models/document_import_body_document.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentImportBodyDocument") + + +@_attrs_define +class DocumentImportBodyDocument: + """ + Attributes: + name (str): + ephemeral (str | Unset): + """ + + name: str + ephemeral: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + ephemeral = self.ephemeral + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + if ephemeral is not UNSET: + field_dict["ephemeral"] = ephemeral + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + name = d.pop("name") + + ephemeral = d.pop("ephemeral", UNSET) + + document_import_body_document = cls( + name=name, + ephemeral=ephemeral, + ) + + document_import_body_document.additional_properties = d + return document_import_body_document + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_import_body_export_version.py b/omni_python_sdk/models/document_import_body_export_version.py new file mode 100644 index 0000000..b16c0ef --- /dev/null +++ b/omni_python_sdk/models/document_import_body_export_version.py @@ -0,0 +1,13 @@ +from typing import Literal + +DocumentImportBodyExportVersion = Literal["0.1"] + +DOCUMENT_IMPORT_BODY_EXPORT_VERSION_VALUES: set[DocumentImportBodyExportVersion] = { + "0.1", +} + + +def check_document_import_body_export_version(value: str) -> DocumentImportBodyExportVersion: + if value in DOCUMENT_IMPORT_BODY_EXPORT_VERSION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENT_IMPORT_BODY_EXPORT_VERSION_VALUES!r}") diff --git a/omni_python_sdk/models/document_import_body_file_uploads.py b/omni_python_sdk/models/document_import_body_file_uploads.py new file mode 100644 index 0000000..922ef5c --- /dev/null +++ b/omni_python_sdk/models/document_import_body_file_uploads.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentImportBodyFileUploads") + + +@_attrs_define +class DocumentImportBodyFileUploads: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + document_import_body_file_uploads = cls() + + document_import_body_file_uploads.additional_properties = d + return document_import_body_file_uploads + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_import_body_query_models.py b/omni_python_sdk/models/document_import_body_query_models.py new file mode 100644 index 0000000..ea726c4 --- /dev/null +++ b/omni_python_sdk/models/document_import_body_query_models.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentImportBodyQueryModels") + + +@_attrs_define +class DocumentImportBodyQueryModels: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + document_import_body_query_models = cls() + + document_import_body_query_models.additional_properties = d + return document_import_body_query_models + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_import_response.py b/omni_python_sdk/models/document_import_response.py new file mode 100644 index 0000000..d4a2cf9 --- /dev/null +++ b/omni_python_sdk/models/document_import_response.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentImportResponse") + + +@_attrs_define +class DocumentImportResponse: + """ + Attributes: + document_id (UUID): ID of the imported document + identifier (str): Document identifier (miniUuid) + """ + + document_id: UUID + identifier: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + document_id = str(self.document_id) + + identifier = self.identifier + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "documentId": document_id, + "identifier": identifier, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + document_id = UUID(d.pop("documentId")) + + identifier = d.pop("identifier") + + document_import_response = cls( + document_id=document_id, + identifier=identifier, + ) + + document_import_response.additional_properties = d + return document_import_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_owner.py b/omni_python_sdk/models/document_owner.py new file mode 100644 index 0000000..48c935d --- /dev/null +++ b/omni_python_sdk/models/document_owner.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentOwner") + + +@_attrs_define +class DocumentOwner: + """Document owner + + Attributes: + id (str): Owner membership ID + name (str): Owner display name + """ + + id: str + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + name = d.pop("name") + + document_owner = cls( + id=id, + name=name, + ) + + document_owner.additional_properties = d + return document_owner + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/document_scope.py b/omni_python_sdk/models/document_scope.py new file mode 100644 index 0000000..302d0b7 --- /dev/null +++ b/omni_python_sdk/models/document_scope.py @@ -0,0 +1,14 @@ +from typing import Literal + +DocumentScope = Literal["organization", "restricted"] + +DOCUMENT_SCOPE_VALUES: set[DocumentScope] = { + "organization", + "restricted", +} + + +def check_document_scope(value: str) -> DocumentScope: + if value in DOCUMENT_SCOPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENT_SCOPE_VALUES!r}") diff --git a/omni_python_sdk/models/document_type.py b/omni_python_sdk/models/document_type.py new file mode 100644 index 0000000..ffcb06e --- /dev/null +++ b/omni_python_sdk/models/document_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +DocumentType = Literal["document"] + +DOCUMENT_TYPE_VALUES: set[DocumentType] = { + "document", +} + + +def check_document_type(value: str) -> DocumentType: + if value in DOCUMENT_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENT_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/documents_access_list_access_source.py b/omni_python_sdk/models/documents_access_list_access_source.py new file mode 100644 index 0000000..8cf9cc3 --- /dev/null +++ b/omni_python_sdk/models/documents_access_list_access_source.py @@ -0,0 +1,14 @@ +from typing import Literal + +DocumentsAccessListAccessSource = Literal["direct", "folder"] + +DOCUMENTS_ACCESS_LIST_ACCESS_SOURCE_VALUES: set[DocumentsAccessListAccessSource] = { + "direct", + "folder", +} + + +def check_documents_access_list_access_source(value: str) -> DocumentsAccessListAccessSource: + if value in DOCUMENTS_ACCESS_LIST_ACCESS_SOURCE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENTS_ACCESS_LIST_ACCESS_SOURCE_VALUES!r}") diff --git a/omni_python_sdk/models/documents_access_list_response.py b/omni_python_sdk/models/documents_access_list_response.py new file mode 100644 index 0000000..579b649 --- /dev/null +++ b/omni_python_sdk/models/documents_access_list_response.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="DocumentsAccessListResponse") + + +@_attrs_define +class DocumentsAccessListResponse: + """ + Attributes: + page_info (PageInfo): + principals (list[Any]): List of users and groups with access + """ + + page_info: PageInfo + principals: list[Any] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + principals = self.principals + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "principals": principals, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + principals = cast(list[Any], d.pop("principals")) + + documents_access_list_response = cls( + page_info=page_info, + principals=principals, + ) + + documents_access_list_response.additional_properties = d + return documents_access_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_access_list_sort_direction.py b/omni_python_sdk/models/documents_access_list_sort_direction.py new file mode 100644 index 0000000..74e9ef2 --- /dev/null +++ b/omni_python_sdk/models/documents_access_list_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +DocumentsAccessListSortDirection = Literal["asc", "desc"] + +DOCUMENTS_ACCESS_LIST_SORT_DIRECTION_VALUES: set[DocumentsAccessListSortDirection] = { + "asc", + "desc", +} + + +def check_documents_access_list_sort_direction(value: str) -> DocumentsAccessListSortDirection: + if value in DOCUMENTS_ACCESS_LIST_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENTS_ACCESS_LIST_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/documents_access_list_type.py b/omni_python_sdk/models/documents_access_list_type.py new file mode 100644 index 0000000..2774160 --- /dev/null +++ b/omni_python_sdk/models/documents_access_list_type.py @@ -0,0 +1,14 @@ +from typing import Literal + +DocumentsAccessListType = Literal["user", "userGroup"] + +DOCUMENTS_ACCESS_LIST_TYPE_VALUES: set[DocumentsAccessListType] = { + "user", + "userGroup", +} + + +def check_documents_access_list_type(value: str) -> DocumentsAccessListType: + if value in DOCUMENTS_ACCESS_LIST_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENTS_ACCESS_LIST_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/documents_add_permits_body.py b/omni_python_sdk/models/documents_add_permits_body.py new file mode 100644 index 0000000..e7c362a --- /dev/null +++ b/omni_python_sdk/models/documents_add_permits_body.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.documents_add_permits_body_role import DocumentsAddPermitsBodyRole, check_documents_add_permits_body_role +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsAddPermitsBody") + + +@_attrs_define +class DocumentsAddPermitsBody: + """ + Attributes: + role (DocumentsAddPermitsBodyRole): Role to grant + access_boost (bool | Unset): Grant access boost Default: False. + user_group_ids (list[str] | Unset): User group IDs to grant access to + user_ids (list[UUID] | Unset): User membership IDs to grant access to + """ + + role: DocumentsAddPermitsBodyRole + access_boost: bool | Unset = False + user_group_ids: list[str] | Unset = UNSET + user_ids: list[UUID] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + role: str = self.role + + access_boost = self.access_boost + + user_group_ids: list[str] | Unset = UNSET + if not isinstance(self.user_group_ids, Unset): + user_group_ids = self.user_group_ids + + user_ids: list[str] | Unset = UNSET + if not isinstance(self.user_ids, Unset): + user_ids = [] + for user_ids_item_data in self.user_ids: + user_ids_item = str(user_ids_item_data) + user_ids.append(user_ids_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "role": role, + } + ) + if access_boost is not UNSET: + field_dict["accessBoost"] = access_boost + if user_group_ids is not UNSET: + field_dict["userGroupIds"] = user_group_ids + if user_ids is not UNSET: + field_dict["userIds"] = user_ids + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + role = check_documents_add_permits_body_role(d.pop("role")) + + access_boost = d.pop("accessBoost", UNSET) + + user_group_ids = cast(list[str], d.pop("userGroupIds", UNSET)) + + _user_ids = d.pop("userIds", UNSET) + user_ids: list[UUID] | Unset = UNSET + if _user_ids is not UNSET: + user_ids = [] + for user_ids_item_data in _user_ids: + user_ids_item = UUID(user_ids_item_data) + + user_ids.append(user_ids_item) + + documents_add_permits_body = cls( + role=role, + access_boost=access_boost, + user_group_ids=user_group_ids, + user_ids=user_ids, + ) + + documents_add_permits_body.additional_properties = d + return documents_add_permits_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_add_permits_body_role.py b/omni_python_sdk/models/documents_add_permits_body_role.py new file mode 100644 index 0000000..3636840 --- /dev/null +++ b/omni_python_sdk/models/documents_add_permits_body_role.py @@ -0,0 +1,17 @@ +from typing import Literal + +DocumentsAddPermitsBodyRole = Literal["EDITOR", "EXPLORER", "MANAGER", "NO_ACCESS", "VIEWER"] + +DOCUMENTS_ADD_PERMITS_BODY_ROLE_VALUES: set[DocumentsAddPermitsBodyRole] = { + "EDITOR", + "EXPLORER", + "MANAGER", + "NO_ACCESS", + "VIEWER", +} + + +def check_documents_add_permits_body_role(value: str) -> DocumentsAddPermitsBodyRole: + if value in DOCUMENTS_ADD_PERMITS_BODY_ROLE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENTS_ADD_PERMITS_BODY_ROLE_VALUES!r}") diff --git a/omni_python_sdk/models/documents_bulk_update_labels_body.py b/omni_python_sdk/models/documents_bulk_update_labels_body.py new file mode 100644 index 0000000..a9ab0ee --- /dev/null +++ b/omni_python_sdk/models/documents_bulk_update_labels_body.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsBulkUpdateLabelsBody") + + +@_attrs_define +class DocumentsBulkUpdateLabelsBody: + """ + Attributes: + add (list[str] | Unset): Labels to add + remove (list[str] | Unset): Labels to remove + """ + + add: list[str] | Unset = UNSET + remove: list[str] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + add: list[str] | Unset = UNSET + if not isinstance(self.add, Unset): + add = self.add + + remove: list[str] | Unset = UNSET + if not isinstance(self.remove, Unset): + remove = self.remove + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if add is not UNSET: + field_dict["add"] = add + if remove is not UNSET: + field_dict["remove"] = remove + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + add = cast(list[str], d.pop("add", UNSET)) + + remove = cast(list[str], d.pop("remove", UNSET)) + + documents_bulk_update_labels_body = cls( + add=add, + remove=remove, + ) + + documents_bulk_update_labels_body.additional_properties = d + return documents_bulk_update_labels_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_bulk_update_labels_response.py b/omni_python_sdk/models/documents_bulk_update_labels_response.py new file mode 100644 index 0000000..4d158ae --- /dev/null +++ b/omni_python_sdk/models/documents_bulk_update_labels_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsBulkUpdateLabelsResponse") + + +@_attrs_define +class DocumentsBulkUpdateLabelsResponse: + """ + Attributes: + labels (list[str]): Updated list of labels on the document + """ + + labels: list[str] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + labels = self.labels + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "labels": labels, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + labels = cast(list[str], d.pop("labels")) + + documents_bulk_update_labels_response = cls( + labels=labels, + ) + + documents_bulk_update_labels_response.additional_properties = d + return documents_bulk_update_labels_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_create_body.py b/omni_python_sdk/models/documents_create_body.py new file mode 100644 index 0000000..d5e9d59 --- /dev/null +++ b/omni_python_sdk/models/documents_create_body.py @@ -0,0 +1,196 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.documents_create_body_query_presentations_item import DocumentsCreateBodyQueryPresentationsItem + + +T = TypeVar("T", bound="DocumentsCreateBody") + + +@_attrs_define +class DocumentsCreateBody: + """ + Attributes: + model_id (str): Shared model ID to base the document on + name (str): Document name + branch_id (UUID | Unset): Optional branch ID to associate the document with a model branch Example: + 123e4567-e89b-12d3-a456-426614174001. + description (None | str | Unset): Document description + facet_filters (bool | Unset): Enable facet filters on the dashboard + filter_config (Any | Unset): Dashboard filter configuration + filter_order (list[str] | Unset): Order of filters in the dashboard + identifier (str | Unset): Optional document identifier. If omitted, an identifier is auto-generated. Must be + unique within the organization. + metadata (Any | Unset): Dashboard metadata + metadata_version (str | Unset): Dashboard metadata version (required when metadata is provided) + query_presentations (list[DocumentsCreateBodyQueryPresentationsItem] | Unset): Query presentations for the + document + """ + + model_id: str + name: str + branch_id: UUID | Unset = UNSET + description: None | str | Unset = UNSET + facet_filters: bool | Unset = UNSET + filter_config: Any | Unset = UNSET + filter_order: list[str] | Unset = UNSET + identifier: str | Unset = UNSET + metadata: Any | Unset = UNSET + metadata_version: str | Unset = UNSET + query_presentations: list[DocumentsCreateBodyQueryPresentationsItem] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + model_id = self.model_id + + name = self.name + + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + facet_filters = self.facet_filters + + filter_config = self.filter_config + + filter_order: list[str] | Unset = UNSET + if not isinstance(self.filter_order, Unset): + filter_order = self.filter_order + + identifier = self.identifier + + metadata = self.metadata + + metadata_version = self.metadata_version + + query_presentations: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.query_presentations, Unset): + query_presentations = [] + for query_presentations_item_data in self.query_presentations: + query_presentations_item = query_presentations_item_data.to_dict() + query_presentations.append(query_presentations_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "modelId": model_id, + "name": name, + } + ) + if branch_id is not UNSET: + field_dict["branchId"] = branch_id + if description is not UNSET: + field_dict["description"] = description + if facet_filters is not UNSET: + field_dict["facetFilters"] = facet_filters + if filter_config is not UNSET: + field_dict["filterConfig"] = filter_config + if filter_order is not UNSET: + field_dict["filterOrder"] = filter_order + if identifier is not UNSET: + field_dict["identifier"] = identifier + if metadata is not UNSET: + field_dict["metadata"] = metadata + if metadata_version is not UNSET: + field_dict["metadataVersion"] = metadata_version + if query_presentations is not UNSET: + field_dict["queryPresentations"] = query_presentations + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.documents_create_body_query_presentations_item import DocumentsCreateBodyQueryPresentationsItem + + d = dict(src_dict) + model_id = d.pop("modelId") + + name = d.pop("name") + + _branch_id = d.pop("branchId", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + facet_filters = d.pop("facetFilters", UNSET) + + filter_config = d.pop("filterConfig", UNSET) + + filter_order = cast(list[str], d.pop("filterOrder", UNSET)) + + identifier = d.pop("identifier", UNSET) + + metadata = d.pop("metadata", UNSET) + + metadata_version = d.pop("metadataVersion", UNSET) + + _query_presentations = d.pop("queryPresentations", UNSET) + query_presentations: list[DocumentsCreateBodyQueryPresentationsItem] | Unset = UNSET + if _query_presentations is not UNSET: + query_presentations = [] + for query_presentations_item_data in _query_presentations: + query_presentations_item = DocumentsCreateBodyQueryPresentationsItem.from_dict( + query_presentations_item_data + ) + + query_presentations.append(query_presentations_item) + + documents_create_body = cls( + model_id=model_id, + name=name, + branch_id=branch_id, + description=description, + facet_filters=facet_filters, + filter_config=filter_config, + filter_order=filter_order, + identifier=identifier, + metadata=metadata, + metadata_version=metadata_version, + query_presentations=query_presentations, + ) + + documents_create_body.additional_properties = d + return documents_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_create_body_query_presentations_item.py b/omni_python_sdk/models/documents_create_body_query_presentations_item.py new file mode 100644 index 0000000..e703795 --- /dev/null +++ b/omni_python_sdk/models/documents_create_body_query_presentations_item.py @@ -0,0 +1,185 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.api_vis_config import ApiVisConfig + from ..models.documents_create_body_query_presentations_item_query import ( + DocumentsCreateBodyQueryPresentationsItemQuery, + ) + + +T = TypeVar("T", bound="DocumentsCreateBodyQueryPresentationsItem") + + +@_attrs_define +class DocumentsCreateBodyQueryPresentationsItem: + """ + Attributes: + name (str): Query presentation name + query (DocumentsCreateBodyQueryPresentationsItemQuery): Query definition + ai_config (Any | Unset): AI configuration + chart_type (None | str | Unset): Chart type + description (str | Unset): Query presentation description + prefers_chart (bool | Unset): Whether to prefer chart view + result_config (Any | Unset): Result configuration + sub_title (str | Unset): Subtitle + topic_name (None | str | Unset): Topic name. Omit or pass null for raw-SQL tiles or any tile with no semantic + topic. + vis_config (ApiVisConfig | Unset): Visualization configuration (Not statically modeled; use plain dicts.) + """ + + name: str + query: DocumentsCreateBodyQueryPresentationsItemQuery + ai_config: Any | Unset = UNSET + chart_type: None | str | Unset = UNSET + description: str | Unset = UNSET + prefers_chart: bool | Unset = UNSET + result_config: Any | Unset = UNSET + sub_title: str | Unset = UNSET + topic_name: None | str | Unset = UNSET + vis_config: ApiVisConfig | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + query = self.query.to_dict() + + ai_config = self.ai_config + + chart_type: None | str | Unset + if isinstance(self.chart_type, Unset): + chart_type = UNSET + else: + chart_type = self.chart_type + + description = self.description + + prefers_chart = self.prefers_chart + + result_config = self.result_config + + sub_title = self.sub_title + + topic_name: None | str | Unset + if isinstance(self.topic_name, Unset): + topic_name = UNSET + else: + topic_name = self.topic_name + + vis_config: dict[str, Any] | Unset = UNSET + if not isinstance(self.vis_config, Unset): + vis_config = self.vis_config.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "query": query, + } + ) + if ai_config is not UNSET: + field_dict["aiConfig"] = ai_config + if chart_type is not UNSET: + field_dict["chartType"] = chart_type + if description is not UNSET: + field_dict["description"] = description + if prefers_chart is not UNSET: + field_dict["prefersChart"] = prefers_chart + if result_config is not UNSET: + field_dict["resultConfig"] = result_config + if sub_title is not UNSET: + field_dict["subTitle"] = sub_title + if topic_name is not UNSET: + field_dict["topicName"] = topic_name + if vis_config is not UNSET: + field_dict["visConfig"] = vis_config + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.api_vis_config import ApiVisConfig + from ..models.documents_create_body_query_presentations_item_query import ( + DocumentsCreateBodyQueryPresentationsItemQuery, + ) + + d = dict(src_dict) + name = d.pop("name") + + query = DocumentsCreateBodyQueryPresentationsItemQuery.from_dict(d.pop("query")) + + ai_config = d.pop("aiConfig", UNSET) + + def _parse_chart_type(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + chart_type = _parse_chart_type(d.pop("chartType", UNSET)) + + description = d.pop("description", UNSET) + + prefers_chart = d.pop("prefersChart", UNSET) + + result_config = d.pop("resultConfig", UNSET) + + sub_title = d.pop("subTitle", UNSET) + + def _parse_topic_name(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + topic_name = _parse_topic_name(d.pop("topicName", UNSET)) + + _vis_config = d.pop("visConfig", UNSET) + vis_config: ApiVisConfig | Unset + if isinstance(_vis_config, Unset): + vis_config = UNSET + else: + vis_config = ApiVisConfig.from_dict(_vis_config) + + documents_create_body_query_presentations_item = cls( + name=name, + query=query, + ai_config=ai_config, + chart_type=chart_type, + description=description, + prefers_chart=prefers_chart, + result_config=result_config, + sub_title=sub_title, + topic_name=topic_name, + vis_config=vis_config, + ) + + documents_create_body_query_presentations_item.additional_properties = d + return documents_create_body_query_presentations_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_create_body_query_presentations_item_query.py b/omni_python_sdk/models/documents_create_body_query_presentations_item_query.py new file mode 100644 index 0000000..f67fcb4 --- /dev/null +++ b/omni_python_sdk/models/documents_create_body_query_presentations_item_query.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsCreateBodyQueryPresentationsItemQuery") + + +@_attrs_define +class DocumentsCreateBodyQueryPresentationsItemQuery: + """Query definition + + Attributes: + fields (list[str]): Query fields + table (str): Query table/topic + """ + + fields: list[str] + table: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + fields = self.fields + + table = self.table + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "fields": fields, + "table": table, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + fields = cast(list[str], d.pop("fields")) + + table = d.pop("table") + + documents_create_body_query_presentations_item_query = cls( + fields=fields, + table=table, + ) + + documents_create_body_query_presentations_item_query.additional_properties = d + return documents_create_body_query_presentations_item_query + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_create_draft_body.py b/omni_python_sdk/models/documents_create_draft_body.py new file mode 100644 index 0000000..f6315ff --- /dev/null +++ b/omni_python_sdk/models/documents_create_draft_body.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsCreateDraftBody") + + +@_attrs_define +class DocumentsCreateDraftBody: + """ + Attributes: + branch_id (UUID | Unset): Branch ID for the draft + """ + + branch_id: UUID | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if branch_id is not UNSET: + field_dict["branchId"] = branch_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + _branch_id = d.pop("branchId", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + documents_create_draft_body = cls( + branch_id=branch_id, + ) + + documents_create_draft_body.additional_properties = d + return documents_create_draft_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_create_draft_response.py b/omni_python_sdk/models/documents_create_draft_response.py new file mode 100644 index 0000000..0cdab54 --- /dev/null +++ b/omni_python_sdk/models/documents_create_draft_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsCreateDraftResponse") + + +@_attrs_define +class DocumentsCreateDraftResponse: + """ + Attributes: + identifier (str): Draft document identifier + """ + + identifier: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + identifier = self.identifier + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "identifier": identifier, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + identifier = d.pop("identifier") + + documents_create_draft_response = cls( + identifier=identifier, + ) + + documents_create_draft_response.additional_properties = d + return documents_create_draft_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_create_response.py b/omni_python_sdk/models/documents_create_response.py new file mode 100644 index 0000000..7c3ba71 --- /dev/null +++ b/omni_python_sdk/models/documents_create_response.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.documents_create_response_dashboard import DocumentsCreateResponseDashboard + from ..models.documents_create_response_workbook import DocumentsCreateResponseWorkbook + + +T = TypeVar("T", bound="DocumentsCreateResponse") + + +@_attrs_define +class DocumentsCreateResponse: + """ + Attributes: + dashboard (DocumentsCreateResponseDashboard): Created dashboard + workbook (DocumentsCreateResponseWorkbook): Created workbook + """ + + dashboard: DocumentsCreateResponseDashboard + workbook: DocumentsCreateResponseWorkbook + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + dashboard = self.dashboard.to_dict() + + workbook = self.workbook.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "dashboard": dashboard, + "workbook": workbook, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.documents_create_response_dashboard import DocumentsCreateResponseDashboard + from ..models.documents_create_response_workbook import DocumentsCreateResponseWorkbook + + d = dict(src_dict) + dashboard = DocumentsCreateResponseDashboard.from_dict(d.pop("dashboard")) + + workbook = DocumentsCreateResponseWorkbook.from_dict(d.pop("workbook")) + + documents_create_response = cls( + dashboard=dashboard, + workbook=workbook, + ) + + documents_create_response.additional_properties = d + return documents_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_create_response_dashboard.py b/omni_python_sdk/models/documents_create_response_dashboard.py new file mode 100644 index 0000000..a95ac26 --- /dev/null +++ b/omni_python_sdk/models/documents_create_response_dashboard.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsCreateResponseDashboard") + + +@_attrs_define +class DocumentsCreateResponseDashboard: + """Created dashboard + + Attributes: + dashboard_id (str): Dashboard ID + id (str): Dashboard ID + """ + + dashboard_id: str + id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + dashboard_id = self.dashboard_id + + id = self.id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "dashboardId": dashboard_id, + "id": id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + dashboard_id = d.pop("dashboardId") + + id = d.pop("id") + + documents_create_response_dashboard = cls( + dashboard_id=dashboard_id, + id=id, + ) + + documents_create_response_dashboard.additional_properties = d + return documents_create_response_dashboard + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_create_response_workbook.py b/omni_python_sdk/models/documents_create_response_workbook.py new file mode 100644 index 0000000..5a2ce12 --- /dev/null +++ b/omni_python_sdk/models/documents_create_response_workbook.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsCreateResponseWorkbook") + + +@_attrs_define +class DocumentsCreateResponseWorkbook: + """Created workbook + + Attributes: + document_id (str): Document ID (deprecated) + id (str): Workbook ID + """ + + document_id: str + id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + document_id = self.document_id + + id = self.id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "documentId": document_id, + "id": id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + document_id = d.pop("documentId") + + id = d.pop("id") + + documents_create_response_workbook = cls( + document_id=document_id, + id=id, + ) + + documents_create_response_workbook.additional_properties = d + return documents_create_response_workbook + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_discard_draft_body.py b/omni_python_sdk/models/documents_discard_draft_body.py new file mode 100644 index 0000000..fd598c5 --- /dev/null +++ b/omni_python_sdk/models/documents_discard_draft_body.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsDiscardDraftBody") + + +@_attrs_define +class DocumentsDiscardDraftBody: + """ + Attributes: + branch_id (UUID | Unset): Branch ID for the draft + """ + + branch_id: UUID | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if branch_id is not UNSET: + field_dict["branchId"] = branch_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + _branch_id = d.pop("branchId", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + documents_discard_draft_body = cls( + branch_id=branch_id, + ) + + documents_discard_draft_body.additional_properties = d + return documents_discard_draft_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_discard_draft_response.py b/omni_python_sdk/models/documents_discard_draft_response.py new file mode 100644 index 0000000..e92f6a2 --- /dev/null +++ b/omni_python_sdk/models/documents_discard_draft_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsDiscardDraftResponse") + + +@_attrs_define +class DocumentsDiscardDraftResponse: + """ + Attributes: + message (str): Success message + """ + + message: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + documents_discard_draft_response = cls( + message=message, + ) + + documents_discard_draft_response.additional_properties = d + return documents_discard_draft_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_duplicate_body.py b/omni_python_sdk/models/documents_duplicate_body.py new file mode 100644 index 0000000..da4a6b9 --- /dev/null +++ b/omni_python_sdk/models/documents_duplicate_body.py @@ -0,0 +1,100 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.documents_duplicate_body_scope import DocumentsDuplicateBodyScope, check_documents_duplicate_body_scope +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsDuplicateBody") + + +@_attrs_define +class DocumentsDuplicateBody: + """ + Attributes: + name (str): Name for the duplicated document + folder_path (None | str | Unset): Destination folder path (null for root) + scope (DocumentsDuplicateBodyScope | Unset): Access scope for the duplicated document + """ + + name: str + folder_path: None | str | Unset = UNSET + scope: DocumentsDuplicateBodyScope | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + folder_path: None | str | Unset + if isinstance(self.folder_path, Unset): + folder_path = UNSET + else: + folder_path = self.folder_path + + scope: str | Unset = UNSET + if not isinstance(self.scope, Unset): + scope = self.scope + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + if folder_path is not UNSET: + field_dict["folderPath"] = folder_path + if scope is not UNSET: + field_dict["scope"] = scope + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + name = d.pop("name") + + def _parse_folder_path(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + folder_path = _parse_folder_path(d.pop("folderPath", UNSET)) + + _scope = d.pop("scope", UNSET) + scope: DocumentsDuplicateBodyScope | Unset + if isinstance(_scope, Unset): + scope = UNSET + else: + scope = check_documents_duplicate_body_scope(_scope) + + documents_duplicate_body = cls( + name=name, + folder_path=folder_path, + scope=scope, + ) + + documents_duplicate_body.additional_properties = d + return documents_duplicate_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_duplicate_body_scope.py b/omni_python_sdk/models/documents_duplicate_body_scope.py new file mode 100644 index 0000000..6549847 --- /dev/null +++ b/omni_python_sdk/models/documents_duplicate_body_scope.py @@ -0,0 +1,14 @@ +from typing import Literal + +DocumentsDuplicateBodyScope = Literal["organization", "restricted"] + +DOCUMENTS_DUPLICATE_BODY_SCOPE_VALUES: set[DocumentsDuplicateBodyScope] = { + "organization", + "restricted", +} + + +def check_documents_duplicate_body_scope(value: str) -> DocumentsDuplicateBodyScope: + if value in DOCUMENTS_DUPLICATE_BODY_SCOPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENTS_DUPLICATE_BODY_SCOPE_VALUES!r}") diff --git a/omni_python_sdk/models/documents_duplicate_response.py b/omni_python_sdk/models/documents_duplicate_response.py new file mode 100644 index 0000000..bbd0263 --- /dev/null +++ b/omni_python_sdk/models/documents_duplicate_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsDuplicateResponse") + + +@_attrs_define +class DocumentsDuplicateResponse: + """ + Attributes: + dashboard_id (str): New dashboard ID + identifier (str): New document identifier + name (str): Document name + workbook_id (str): New workbook ID + """ + + dashboard_id: str + identifier: str + name: str + workbook_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + dashboard_id = self.dashboard_id + + identifier = self.identifier + + name = self.name + + workbook_id = self.workbook_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "dashboardId": dashboard_id, + "identifier": identifier, + "name": name, + "workbookId": workbook_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + dashboard_id = d.pop("dashboardId") + + identifier = d.pop("identifier") + + name = d.pop("name") + + workbook_id = d.pop("workbookId") + + documents_duplicate_response = cls( + dashboard_id=dashboard_id, + identifier=identifier, + name=name, + workbook_id=workbook_id, + ) + + documents_duplicate_response.additional_properties = d + return documents_duplicate_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_get_permissions_response.py b/omni_python_sdk/models/documents_get_permissions_response.py new file mode 100644 index 0000000..dc7e092 --- /dev/null +++ b/omni_python_sdk/models/documents_get_permissions_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsGetPermissionsResponse") + + +@_attrs_define +class DocumentsGetPermissionsResponse: + """ + Attributes: + permits (Any | Unset): User permits for the document + """ + + permits: Any | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + permits = self.permits + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if permits is not UNSET: + field_dict["permits"] = permits + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + permits = d.pop("permits", UNSET) + + documents_get_permissions_response = cls( + permits=permits, + ) + + documents_get_permissions_response.additional_properties = d + return documents_get_permissions_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_get_queries_response.py b/omni_python_sdk/models/documents_get_queries_response.py new file mode 100644 index 0000000..c369261 --- /dev/null +++ b/omni_python_sdk/models/documents_get_queries_response.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.documents_get_queries_response_queries_item import DocumentsGetQueriesResponseQueriesItem + + +T = TypeVar("T", bound="DocumentsGetQueriesResponse") + + +@_attrs_define +class DocumentsGetQueriesResponse: + """ + Attributes: + queries (list[DocumentsGetQueriesResponseQueriesItem]): List of queries in the document + """ + + queries: list[DocumentsGetQueriesResponseQueriesItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + queries = [] + for queries_item_data in self.queries: + queries_item = queries_item_data.to_dict() + queries.append(queries_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "queries": queries, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.documents_get_queries_response_queries_item import DocumentsGetQueriesResponseQueriesItem + + d = dict(src_dict) + queries = [] + _queries = d.pop("queries") + for queries_item_data in _queries: + queries_item = DocumentsGetQueriesResponseQueriesItem.from_dict(queries_item_data) + + queries.append(queries_item) + + documents_get_queries_response = cls( + queries=queries, + ) + + documents_get_queries_response.additional_properties = d + return documents_get_queries_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_get_queries_response_queries_item.py b/omni_python_sdk/models/documents_get_queries_response_queries_item.py new file mode 100644 index 0000000..6018c3b --- /dev/null +++ b/omni_python_sdk/models/documents_get_queries_response_queries_item.py @@ -0,0 +1,96 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsGetQueriesResponseQueriesItem") + + +@_attrs_define +class DocumentsGetQueriesResponseQueriesItem: + """ + Attributes: + id (str): Query presentation ID + name (str): Query presentation name + query_identifier_map_key (str): Key in the query identifier map + url (str): URL to view this specific query/sheet in the workbook. Example: https://org.omni.co/w/abc123?key=1. + query (Any | Unset): Query JSON definition + """ + + id: str + name: str + query_identifier_map_key: str + url: str + query: Any | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + query_identifier_map_key = self.query_identifier_map_key + + url = self.url + + query = self.query + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + "queryIdentifierMapKey": query_identifier_map_key, + "url": url, + } + ) + if query is not UNSET: + field_dict["query"] = query + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + name = d.pop("name") + + query_identifier_map_key = d.pop("queryIdentifierMapKey") + + url = d.pop("url") + + query = d.pop("query", UNSET) + + documents_get_queries_response_queries_item = cls( + id=id, + name=name, + query_identifier_map_key=query_identifier_map_key, + url=url, + query=query, + ) + + documents_get_queries_response_queries_item.additional_properties = d + return documents_get_queries_response_queries_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_get_response.py b/omni_python_sdk/models/documents_get_response.py new file mode 100644 index 0000000..df64516 --- /dev/null +++ b/omni_python_sdk/models/documents_get_response.py @@ -0,0 +1,147 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsGetResponse") + + +@_attrs_define +class DocumentsGetResponse: + """ + Attributes: + facet_filters (bool): Whether facet filters are enabled + filter_order (list[str]): Order of filters + model_id (str): Model ID + name (str): Document name + query_presentations (list[Any]): Query presentations + refresh_interval (float | None): Auto-refresh interval in seconds + description (None | str | Unset): Document description + document_metadata (Any | Unset): Document metadata + filter_config (Any | Unset): Dashboard filter configuration + """ + + facet_filters: bool + filter_order: list[str] + model_id: str + name: str + query_presentations: list[Any] + refresh_interval: float | None + description: None | str | Unset = UNSET + document_metadata: Any | Unset = UNSET + filter_config: Any | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + facet_filters = self.facet_filters + + filter_order = self.filter_order + + model_id = self.model_id + + name = self.name + + query_presentations = self.query_presentations + + refresh_interval: float | None + refresh_interval = self.refresh_interval + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + document_metadata = self.document_metadata + + filter_config = self.filter_config + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "facetFilters": facet_filters, + "filterOrder": filter_order, + "modelId": model_id, + "name": name, + "queryPresentations": query_presentations, + "refreshInterval": refresh_interval, + } + ) + if description is not UNSET: + field_dict["description"] = description + if document_metadata is not UNSET: + field_dict["documentMetadata"] = document_metadata + if filter_config is not UNSET: + field_dict["filterConfig"] = filter_config + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + facet_filters = d.pop("facetFilters") + + filter_order = cast(list[str], d.pop("filterOrder")) + + model_id = d.pop("modelId") + + name = d.pop("name") + + query_presentations = cast(list[Any], d.pop("queryPresentations")) + + def _parse_refresh_interval(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + refresh_interval = _parse_refresh_interval(d.pop("refreshInterval")) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + document_metadata = d.pop("documentMetadata", UNSET) + + filter_config = d.pop("filterConfig", UNSET) + + documents_get_response = cls( + facet_filters=facet_filters, + filter_order=filter_order, + model_id=model_id, + name=name, + query_presentations=query_presentations, + refresh_interval=refresh_interval, + description=description, + document_metadata=document_metadata, + filter_config=filter_config, + ) + + documents_get_response.additional_properties = d + return documents_get_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_list_favorites_response.py b/omni_python_sdk/models/documents_list_favorites_response.py new file mode 100644 index 0000000..23d1b87 --- /dev/null +++ b/omni_python_sdk/models/documents_list_favorites_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.document_favorite_user import DocumentFavoriteUser + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="DocumentsListFavoritesResponse") + + +@_attrs_define +class DocumentsListFavoritesResponse: + """ + Attributes: + page_info (PageInfo): + records (list[DocumentFavoriteUser]): Users who favorited this document + """ + + page_info: PageInfo + records: list[DocumentFavoriteUser] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.document_favorite_user import DocumentFavoriteUser + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = DocumentFavoriteUser.from_dict(records_item_data) + + records.append(records_item) + + documents_list_favorites_response = cls( + page_info=page_info, + records=records, + ) + + documents_list_favorites_response.additional_properties = d + return documents_list_favorites_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_list_favorites_sort_direction.py b/omni_python_sdk/models/documents_list_favorites_sort_direction.py new file mode 100644 index 0000000..7e059d6 --- /dev/null +++ b/omni_python_sdk/models/documents_list_favorites_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +DocumentsListFavoritesSortDirection = Literal["asc", "desc"] + +DOCUMENTS_LIST_FAVORITES_SORT_DIRECTION_VALUES: set[DocumentsListFavoritesSortDirection] = { + "asc", + "desc", +} + + +def check_documents_list_favorites_sort_direction(value: str) -> DocumentsListFavoritesSortDirection: + if value in DOCUMENTS_LIST_FAVORITES_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENTS_LIST_FAVORITES_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/documents_list_response.py b/omni_python_sdk/models/documents_list_response.py new file mode 100644 index 0000000..a4a8e65 --- /dev/null +++ b/omni_python_sdk/models/documents_list_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.document import Document + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="DocumentsListResponse") + + +@_attrs_define +class DocumentsListResponse: + """ + Attributes: + page_info (PageInfo): + records (list[Document]): List of documents + """ + + page_info: PageInfo + records: list[Document] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.document import Document + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = Document.from_dict(records_item_data) + + records.append(records_item) + + documents_list_response = cls( + page_info=page_info, + records=records, + ) + + documents_list_response.additional_properties = d + return documents_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_list_sort_direction.py b/omni_python_sdk/models/documents_list_sort_direction.py new file mode 100644 index 0000000..7a80313 --- /dev/null +++ b/omni_python_sdk/models/documents_list_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +DocumentsListSortDirection = Literal["asc", "desc"] + +DOCUMENTS_LIST_SORT_DIRECTION_VALUES: set[DocumentsListSortDirection] = { + "asc", + "desc", +} + + +def check_documents_list_sort_direction(value: str) -> DocumentsListSortDirection: + if value in DOCUMENTS_LIST_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENTS_LIST_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/documents_list_sort_field.py b/omni_python_sdk/models/documents_list_sort_field.py new file mode 100644 index 0000000..532e40d --- /dev/null +++ b/omni_python_sdk/models/documents_list_sort_field.py @@ -0,0 +1,16 @@ +from typing import Literal + +DocumentsListSortField = Literal["favorites", "name", "updatedAt", "visits"] + +DOCUMENTS_LIST_SORT_FIELD_VALUES: set[DocumentsListSortField] = { + "favorites", + "name", + "updatedAt", + "visits", +} + + +def check_documents_list_sort_field(value: str) -> DocumentsListSortField: + if value in DOCUMENTS_LIST_SORT_FIELD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENTS_LIST_SORT_FIELD_VALUES!r}") diff --git a/omni_python_sdk/models/documents_move_body.py b/omni_python_sdk/models/documents_move_body.py new file mode 100644 index 0000000..d1c48e5 --- /dev/null +++ b/omni_python_sdk/models/documents_move_body.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.documents_move_body_scope import DocumentsMoveBodyScope, check_documents_move_body_scope +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsMoveBody") + + +@_attrs_define +class DocumentsMoveBody: + """ + Attributes: + folder_path (None | str): Destination folder path (null for root) + scope (DocumentsMoveBodyScope | Unset): Access scope for the document + """ + + folder_path: None | str + scope: DocumentsMoveBodyScope | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + folder_path: None | str + folder_path = self.folder_path + + scope: str | Unset = UNSET + if not isinstance(self.scope, Unset): + scope = self.scope + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "folderPath": folder_path, + } + ) + if scope is not UNSET: + field_dict["scope"] = scope + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_folder_path(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + folder_path = _parse_folder_path(d.pop("folderPath")) + + _scope = d.pop("scope", UNSET) + scope: DocumentsMoveBodyScope | Unset + if isinstance(_scope, Unset): + scope = UNSET + else: + scope = check_documents_move_body_scope(_scope) + + documents_move_body = cls( + folder_path=folder_path, + scope=scope, + ) + + documents_move_body.additional_properties = d + return documents_move_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_move_body_scope.py b/omni_python_sdk/models/documents_move_body_scope.py new file mode 100644 index 0000000..15e1099 --- /dev/null +++ b/omni_python_sdk/models/documents_move_body_scope.py @@ -0,0 +1,14 @@ +from typing import Literal + +DocumentsMoveBodyScope = Literal["organization", "restricted"] + +DOCUMENTS_MOVE_BODY_SCOPE_VALUES: set[DocumentsMoveBodyScope] = { + "organization", + "restricted", +} + + +def check_documents_move_body_scope(value: str) -> DocumentsMoveBodyScope: + if value in DOCUMENTS_MOVE_BODY_SCOPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENTS_MOVE_BODY_SCOPE_VALUES!r}") diff --git a/omni_python_sdk/models/documents_put_body.py b/omni_python_sdk/models/documents_put_body.py new file mode 100644 index 0000000..f527f8f --- /dev/null +++ b/omni_python_sdk/models/documents_put_body.py @@ -0,0 +1,171 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.documents_put_query_presentation import DocumentsPutQueryPresentation + + +T = TypeVar("T", bound="DocumentsPutBody") + + +@_attrs_define +class DocumentsPutBody: + """ + Attributes: + facet_filters (bool): Enable facet filters + filter_order (list[str]): Order of filters + model_id (str): Model ID + name (str): Document name + query_presentations (list[DocumentsPutQueryPresentation]): Query presentations (full replacement) + refresh_interval (int | None): Auto-refresh interval in seconds + clear_existing_draft (bool | Unset): Clear existing draft before updating (for published documents with drafts) + Default: False. + description (None | str | Unset): Document description + document_metadata (Any | Unset): Document presentation metadata + filter_config (Any | Unset): Filter configuration + """ + + facet_filters: bool + filter_order: list[str] + model_id: str + name: str + query_presentations: list[DocumentsPutQueryPresentation] + refresh_interval: int | None + clear_existing_draft: bool | Unset = False + description: None | str | Unset = UNSET + document_metadata: Any | Unset = UNSET + filter_config: Any | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + facet_filters = self.facet_filters + + filter_order = self.filter_order + + model_id = self.model_id + + name = self.name + + query_presentations = [] + for query_presentations_item_data in self.query_presentations: + query_presentations_item = query_presentations_item_data.to_dict() + query_presentations.append(query_presentations_item) + + refresh_interval: int | None + refresh_interval = self.refresh_interval + + clear_existing_draft = self.clear_existing_draft + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + document_metadata = self.document_metadata + + filter_config = self.filter_config + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "facetFilters": facet_filters, + "filterOrder": filter_order, + "modelId": model_id, + "name": name, + "queryPresentations": query_presentations, + "refreshInterval": refresh_interval, + } + ) + if clear_existing_draft is not UNSET: + field_dict["clearExistingDraft"] = clear_existing_draft + if description is not UNSET: + field_dict["description"] = description + if document_metadata is not UNSET: + field_dict["documentMetadata"] = document_metadata + if filter_config is not UNSET: + field_dict["filterConfig"] = filter_config + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.documents_put_query_presentation import DocumentsPutQueryPresentation + + d = dict(src_dict) + facet_filters = d.pop("facetFilters") + + filter_order = cast(list[str], d.pop("filterOrder")) + + model_id = d.pop("modelId") + + name = d.pop("name") + + query_presentations = [] + _query_presentations = d.pop("queryPresentations") + for query_presentations_item_data in _query_presentations: + query_presentations_item = DocumentsPutQueryPresentation.from_dict(query_presentations_item_data) + + query_presentations.append(query_presentations_item) + + def _parse_refresh_interval(data: object) -> int | None: + if data is None: + return data + return cast(int | None, data) + + refresh_interval = _parse_refresh_interval(d.pop("refreshInterval")) + + clear_existing_draft = d.pop("clearExistingDraft", UNSET) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + document_metadata = d.pop("documentMetadata", UNSET) + + filter_config = d.pop("filterConfig", UNSET) + + documents_put_body = cls( + facet_filters=facet_filters, + filter_order=filter_order, + model_id=model_id, + name=name, + query_presentations=query_presentations, + refresh_interval=refresh_interval, + clear_existing_draft=clear_existing_draft, + description=description, + document_metadata=document_metadata, + filter_config=filter_config, + ) + + documents_put_body.additional_properties = d + return documents_put_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_put_query_presentation.py b/omni_python_sdk/models/documents_put_query_presentation.py new file mode 100644 index 0000000..974aa2b --- /dev/null +++ b/omni_python_sdk/models/documents_put_query_presentation.py @@ -0,0 +1,264 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.documents_put_query_presentation_chart_type_type_1 import ( + DocumentsPutQueryPresentationChartTypeType1, + check_documents_put_query_presentation_chart_type_type_1, +) +from ..models.documents_put_query_presentation_chart_type_type_2_type_1 import ( + DocumentsPutQueryPresentationChartTypeType2Type1, + check_documents_put_query_presentation_chart_type_type_2_type_1, +) +from ..models.documents_put_query_presentation_chart_type_type_3_type_1 import ( + DocumentsPutQueryPresentationChartTypeType3Type1, + check_documents_put_query_presentation_chart_type_type_3_type_1, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.api_vis_config import ApiVisConfig + from ..models.documents_put_query_presentation_ai_config import DocumentsPutQueryPresentationAiConfig + + +T = TypeVar("T", bound="DocumentsPutQueryPresentation") + + +@_attrs_define +class DocumentsPutQueryPresentation: + """ + Attributes: + name (str): Query presentation name + ai_config (DocumentsPutQueryPresentationAiConfig | Unset): AI configuration + chart_type (DocumentsPutQueryPresentationChartTypeType1 | DocumentsPutQueryPresentationChartTypeType2Type1 | + DocumentsPutQueryPresentationChartTypeType3Type1 | None | Unset): Chart type + description (str | Unset): Description + prefers_chart (bool | Unset): Whether to prefer chart view + query (Any | Unset): Query definition + query_identifier_map_key (str | Unset): Round-trip preservation hint. When the value matches an existing key on + the document, the tile keeps its map key (and dashboard containers stay attached). Omit for new tiles. Must be a + positive integer string (e.g. "1", "2", "10"). + result_config (Any | Unset): Result config + sub_title (str | Unset): Subtitle + topic_name (None | str | Unset): Topic name. Omit or pass null for raw-SQL tiles or any tile with no semantic + topic. + vis_config (ApiVisConfig | Unset): Visualization configuration (Not statically modeled; use plain dicts.) + """ + + name: str + ai_config: DocumentsPutQueryPresentationAiConfig | Unset = UNSET + chart_type: ( + DocumentsPutQueryPresentationChartTypeType1 + | DocumentsPutQueryPresentationChartTypeType2Type1 + | DocumentsPutQueryPresentationChartTypeType3Type1 + | None + | Unset + ) = UNSET + description: str | Unset = UNSET + prefers_chart: bool | Unset = UNSET + query: Any | Unset = UNSET + query_identifier_map_key: str | Unset = UNSET + result_config: Any | Unset = UNSET + sub_title: str | Unset = UNSET + topic_name: None | str | Unset = UNSET + vis_config: ApiVisConfig | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + ai_config: dict[str, Any] | Unset = UNSET + if not isinstance(self.ai_config, Unset): + ai_config = self.ai_config.to_dict() + + chart_type: None | str | Unset + if isinstance(self.chart_type, Unset): + chart_type = UNSET + elif isinstance(self.chart_type, str): + chart_type = self.chart_type + elif isinstance(self.chart_type, str): + chart_type = self.chart_type + elif isinstance(self.chart_type, str): + chart_type = self.chart_type + else: + chart_type = self.chart_type + + description = self.description + + prefers_chart = self.prefers_chart + + query = self.query + + query_identifier_map_key = self.query_identifier_map_key + + result_config = self.result_config + + sub_title = self.sub_title + + topic_name: None | str | Unset + if isinstance(self.topic_name, Unset): + topic_name = UNSET + else: + topic_name = self.topic_name + + vis_config: dict[str, Any] | Unset = UNSET + if not isinstance(self.vis_config, Unset): + vis_config = self.vis_config.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + if ai_config is not UNSET: + field_dict["aiConfig"] = ai_config + if chart_type is not UNSET: + field_dict["chartType"] = chart_type + if description is not UNSET: + field_dict["description"] = description + if prefers_chart is not UNSET: + field_dict["prefersChart"] = prefers_chart + if query is not UNSET: + field_dict["query"] = query + if query_identifier_map_key is not UNSET: + field_dict["queryIdentifierMapKey"] = query_identifier_map_key + if result_config is not UNSET: + field_dict["resultConfig"] = result_config + if sub_title is not UNSET: + field_dict["subTitle"] = sub_title + if topic_name is not UNSET: + field_dict["topicName"] = topic_name + if vis_config is not UNSET: + field_dict["visConfig"] = vis_config + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.api_vis_config import ApiVisConfig + from ..models.documents_put_query_presentation_ai_config import DocumentsPutQueryPresentationAiConfig + + d = dict(src_dict) + name = d.pop("name") + + _ai_config = d.pop("aiConfig", UNSET) + ai_config: DocumentsPutQueryPresentationAiConfig | Unset + if isinstance(_ai_config, Unset): + ai_config = UNSET + else: + ai_config = DocumentsPutQueryPresentationAiConfig.from_dict(_ai_config) + + def _parse_chart_type( + data: object, + ) -> ( + DocumentsPutQueryPresentationChartTypeType1 + | DocumentsPutQueryPresentationChartTypeType2Type1 + | DocumentsPutQueryPresentationChartTypeType3Type1 + | None + | Unset + ): + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + chart_type_type_1 = check_documents_put_query_presentation_chart_type_type_1(data) + + return chart_type_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, str): + raise TypeError() + chart_type_type_2_type_1 = check_documents_put_query_presentation_chart_type_type_2_type_1(data) + + return chart_type_type_2_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, str): + raise TypeError() + chart_type_type_3_type_1 = check_documents_put_query_presentation_chart_type_type_3_type_1(data) + + return chart_type_type_3_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast( + DocumentsPutQueryPresentationChartTypeType1 + | DocumentsPutQueryPresentationChartTypeType2Type1 + | DocumentsPutQueryPresentationChartTypeType3Type1 + | None + | Unset, + data, + ) + + chart_type = _parse_chart_type(d.pop("chartType", UNSET)) + + description = d.pop("description", UNSET) + + prefers_chart = d.pop("prefersChart", UNSET) + + query = d.pop("query", UNSET) + + query_identifier_map_key = d.pop("queryIdentifierMapKey", UNSET) + + result_config = d.pop("resultConfig", UNSET) + + sub_title = d.pop("subTitle", UNSET) + + def _parse_topic_name(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + topic_name = _parse_topic_name(d.pop("topicName", UNSET)) + + _vis_config = d.pop("visConfig", UNSET) + vis_config: ApiVisConfig | Unset + if isinstance(_vis_config, Unset): + vis_config = UNSET + else: + vis_config = ApiVisConfig.from_dict(_vis_config) + + documents_put_query_presentation = cls( + name=name, + ai_config=ai_config, + chart_type=chart_type, + description=description, + prefers_chart=prefers_chart, + query=query, + query_identifier_map_key=query_identifier_map_key, + result_config=result_config, + sub_title=sub_title, + topic_name=topic_name, + vis_config=vis_config, + ) + + documents_put_query_presentation.additional_properties = d + return documents_put_query_presentation + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_put_query_presentation_ai_config.py b/omni_python_sdk/models/documents_put_query_presentation_ai_config.py new file mode 100644 index 0000000..f1fd6aa --- /dev/null +++ b/omni_python_sdk/models/documents_put_query_presentation_ai_config.py @@ -0,0 +1,101 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.documents_put_query_presentation_ai_config_description import ( + DocumentsPutQueryPresentationAiConfigDescription, + ) + from ..models.documents_put_query_presentation_ai_config_sub_title import ( + DocumentsPutQueryPresentationAiConfigSubTitle, + ) + + +T = TypeVar("T", bound="DocumentsPutQueryPresentationAiConfig") + + +@_attrs_define +class DocumentsPutQueryPresentationAiConfig: + """AI configuration + + Attributes: + description (DocumentsPutQueryPresentationAiConfigDescription | Unset): + sub_title (DocumentsPutQueryPresentationAiConfigSubTitle | Unset): + """ + + description: DocumentsPutQueryPresentationAiConfigDescription | Unset = UNSET + sub_title: DocumentsPutQueryPresentationAiConfigSubTitle | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + description: dict[str, Any] | Unset = UNSET + if not isinstance(self.description, Unset): + description = self.description.to_dict() + + sub_title: dict[str, Any] | Unset = UNSET + if not isinstance(self.sub_title, Unset): + sub_title = self.sub_title.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if description is not UNSET: + field_dict["description"] = description + if sub_title is not UNSET: + field_dict["subTitle"] = sub_title + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.documents_put_query_presentation_ai_config_description import ( + DocumentsPutQueryPresentationAiConfigDescription, + ) + from ..models.documents_put_query_presentation_ai_config_sub_title import ( + DocumentsPutQueryPresentationAiConfigSubTitle, + ) + + d = dict(src_dict) + _description = d.pop("description", UNSET) + description: DocumentsPutQueryPresentationAiConfigDescription | Unset + if isinstance(_description, Unset): + description = UNSET + else: + description = DocumentsPutQueryPresentationAiConfigDescription.from_dict(_description) + + _sub_title = d.pop("subTitle", UNSET) + sub_title: DocumentsPutQueryPresentationAiConfigSubTitle | Unset + if isinstance(_sub_title, Unset): + sub_title = UNSET + else: + sub_title = DocumentsPutQueryPresentationAiConfigSubTitle.from_dict(_sub_title) + + documents_put_query_presentation_ai_config = cls( + description=description, + sub_title=sub_title, + ) + + documents_put_query_presentation_ai_config.additional_properties = d + return documents_put_query_presentation_ai_config + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_put_query_presentation_ai_config_description.py b/omni_python_sdk/models/documents_put_query_presentation_ai_config_description.py new file mode 100644 index 0000000..1f8f5d8 --- /dev/null +++ b/omni_python_sdk/models/documents_put_query_presentation_ai_config_description.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsPutQueryPresentationAiConfigDescription") + + +@_attrs_define +class DocumentsPutQueryPresentationAiConfigDescription: + """ + Attributes: + ai_context (str | Unset): + enabled (bool | Unset): + """ + + ai_context: str | Unset = UNSET + enabled: bool | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + ai_context = self.ai_context + + enabled = self.enabled + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if ai_context is not UNSET: + field_dict["aiContext"] = ai_context + if enabled is not UNSET: + field_dict["enabled"] = enabled + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + ai_context = d.pop("aiContext", UNSET) + + enabled = d.pop("enabled", UNSET) + + documents_put_query_presentation_ai_config_description = cls( + ai_context=ai_context, + enabled=enabled, + ) + + documents_put_query_presentation_ai_config_description.additional_properties = d + return documents_put_query_presentation_ai_config_description + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_put_query_presentation_ai_config_sub_title.py b/omni_python_sdk/models/documents_put_query_presentation_ai_config_sub_title.py new file mode 100644 index 0000000..b22db61 --- /dev/null +++ b/omni_python_sdk/models/documents_put_query_presentation_ai_config_sub_title.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsPutQueryPresentationAiConfigSubTitle") + + +@_attrs_define +class DocumentsPutQueryPresentationAiConfigSubTitle: + """ + Attributes: + ai_context (str | Unset): + enabled (bool | Unset): + """ + + ai_context: str | Unset = UNSET + enabled: bool | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + ai_context = self.ai_context + + enabled = self.enabled + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if ai_context is not UNSET: + field_dict["aiContext"] = ai_context + if enabled is not UNSET: + field_dict["enabled"] = enabled + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + ai_context = d.pop("aiContext", UNSET) + + enabled = d.pop("enabled", UNSET) + + documents_put_query_presentation_ai_config_sub_title = cls( + ai_context=ai_context, + enabled=enabled, + ) + + documents_put_query_presentation_ai_config_sub_title.additional_properties = d + return documents_put_query_presentation_ai_config_sub_title + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_put_query_presentation_chart_type_type_1.py b/omni_python_sdk/models/documents_put_query_presentation_chart_type_type_1.py new file mode 100644 index 0000000..e83c10e --- /dev/null +++ b/omni_python_sdk/models/documents_put_query_presentation_chart_type_type_1.py @@ -0,0 +1,87 @@ +from typing import Literal + +DocumentsPutQueryPresentationChartTypeType1 = Literal[ + "area", + "areaStacked", + "areaStackedPercentage", + "auto", + "bar", + "barGrouped", + "barLine", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "funnel", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "markdown", + "omni-ai-summary-markdown", + "omni-spreadsheet", + "pie", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "regionMap", + "sankey", + "singleRecord", + "summaryValue", + "svgMap", + "table", + "treemap", +] + +DOCUMENTS_PUT_QUERY_PRESENTATION_CHART_TYPE_TYPE_1_VALUES: set[DocumentsPutQueryPresentationChartTypeType1] = { + "area", + "areaStacked", + "areaStackedPercentage", + "auto", + "bar", + "barGrouped", + "barLine", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "funnel", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "markdown", + "omni-ai-summary-markdown", + "omni-spreadsheet", + "pie", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "regionMap", + "sankey", + "singleRecord", + "summaryValue", + "svgMap", + "table", + "treemap", +} + + +def check_documents_put_query_presentation_chart_type_type_1(value: str) -> DocumentsPutQueryPresentationChartTypeType1: + if value in DOCUMENTS_PUT_QUERY_PRESENTATION_CHART_TYPE_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {DOCUMENTS_PUT_QUERY_PRESENTATION_CHART_TYPE_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/documents_put_query_presentation_chart_type_type_2_type_1.py b/omni_python_sdk/models/documents_put_query_presentation_chart_type_type_2_type_1.py new file mode 100644 index 0000000..f6a4c9e --- /dev/null +++ b/omni_python_sdk/models/documents_put_query_presentation_chart_type_type_2_type_1.py @@ -0,0 +1,91 @@ +from typing import Literal + +DocumentsPutQueryPresentationChartTypeType2Type1 = Literal[ + "area", + "areaStacked", + "areaStackedPercentage", + "auto", + "bar", + "barGrouped", + "barLine", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "funnel", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "markdown", + "omni-ai-summary-markdown", + "omni-spreadsheet", + "pie", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "regionMap", + "sankey", + "singleRecord", + "summaryValue", + "svgMap", + "table", + "treemap", +] + +DOCUMENTS_PUT_QUERY_PRESENTATION_CHART_TYPE_TYPE_2_TYPE_1_VALUES: set[ + DocumentsPutQueryPresentationChartTypeType2Type1 +] = { + "area", + "areaStacked", + "areaStackedPercentage", + "auto", + "bar", + "barGrouped", + "barLine", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "funnel", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "markdown", + "omni-ai-summary-markdown", + "omni-spreadsheet", + "pie", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "regionMap", + "sankey", + "singleRecord", + "summaryValue", + "svgMap", + "table", + "treemap", +} + + +def check_documents_put_query_presentation_chart_type_type_2_type_1( + value: str, +) -> DocumentsPutQueryPresentationChartTypeType2Type1: + if value in DOCUMENTS_PUT_QUERY_PRESENTATION_CHART_TYPE_TYPE_2_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {DOCUMENTS_PUT_QUERY_PRESENTATION_CHART_TYPE_TYPE_2_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/documents_put_query_presentation_chart_type_type_3_type_1.py b/omni_python_sdk/models/documents_put_query_presentation_chart_type_type_3_type_1.py new file mode 100644 index 0000000..8cab278 --- /dev/null +++ b/omni_python_sdk/models/documents_put_query_presentation_chart_type_type_3_type_1.py @@ -0,0 +1,91 @@ +from typing import Literal + +DocumentsPutQueryPresentationChartTypeType3Type1 = Literal[ + "area", + "areaStacked", + "areaStackedPercentage", + "auto", + "bar", + "barGrouped", + "barLine", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "funnel", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "markdown", + "omni-ai-summary-markdown", + "omni-spreadsheet", + "pie", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "regionMap", + "sankey", + "singleRecord", + "summaryValue", + "svgMap", + "table", + "treemap", +] + +DOCUMENTS_PUT_QUERY_PRESENTATION_CHART_TYPE_TYPE_3_TYPE_1_VALUES: set[ + DocumentsPutQueryPresentationChartTypeType3Type1 +] = { + "area", + "areaStacked", + "areaStackedPercentage", + "auto", + "bar", + "barGrouped", + "barLine", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "funnel", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "markdown", + "omni-ai-summary-markdown", + "omni-spreadsheet", + "pie", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "regionMap", + "sankey", + "singleRecord", + "summaryValue", + "svgMap", + "table", + "treemap", +} + + +def check_documents_put_query_presentation_chart_type_type_3_type_1( + value: str, +) -> DocumentsPutQueryPresentationChartTypeType3Type1: + if value in DOCUMENTS_PUT_QUERY_PRESENTATION_CHART_TYPE_TYPE_3_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {DOCUMENTS_PUT_QUERY_PRESENTATION_CHART_TYPE_TYPE_3_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/documents_put_response.py b/omni_python_sdk/models/documents_put_response.py new file mode 100644 index 0000000..84f39e7 --- /dev/null +++ b/omni_python_sdk/models/documents_put_response.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsPutResponse") + + +@_attrs_define +class DocumentsPutResponse: + """ + Attributes: + identifier (str): Document identifier + name (str): Updated document name + description (None | str | Unset): Document description + """ + + identifier: str + name: str + description: None | str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + identifier = self.identifier + + name = self.name + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "identifier": identifier, + "name": name, + } + ) + if description is not UNSET: + field_dict["description"] = description + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + identifier = d.pop("identifier") + + name = d.pop("name") + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + documents_put_response = cls( + identifier=identifier, + name=name, + description=description, + ) + + documents_put_response.additional_properties = d + return documents_put_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_revoke_permits_body.py b/omni_python_sdk/models/documents_revoke_permits_body.py new file mode 100644 index 0000000..fb8f550 --- /dev/null +++ b/omni_python_sdk/models/documents_revoke_permits_body.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsRevokePermitsBody") + + +@_attrs_define +class DocumentsRevokePermitsBody: + """ + Attributes: + user_group_ids (list[str] | Unset): User group IDs to revoke access from + user_ids (list[UUID] | Unset): User membership IDs to revoke access from + """ + + user_group_ids: list[str] | Unset = UNSET + user_ids: list[UUID] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + user_group_ids: list[str] | Unset = UNSET + if not isinstance(self.user_group_ids, Unset): + user_group_ids = self.user_group_ids + + user_ids: list[str] | Unset = UNSET + if not isinstance(self.user_ids, Unset): + user_ids = [] + for user_ids_item_data in self.user_ids: + user_ids_item = str(user_ids_item_data) + user_ids.append(user_ids_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if user_group_ids is not UNSET: + field_dict["userGroupIds"] = user_group_ids + if user_ids is not UNSET: + field_dict["userIds"] = user_ids + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + user_group_ids = cast(list[str], d.pop("userGroupIds", UNSET)) + + _user_ids = d.pop("userIds", UNSET) + user_ids: list[UUID] | Unset = UNSET + if _user_ids is not UNSET: + user_ids = [] + for user_ids_item_data in _user_ids: + user_ids_item = UUID(user_ids_item_data) + + user_ids.append(user_ids_item) + + documents_revoke_permits_body = cls( + user_group_ids=user_group_ids, + user_ids=user_ids, + ) + + documents_revoke_permits_body.additional_properties = d + return documents_revoke_permits_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_transfer_ownership_body.py b/omni_python_sdk/models/documents_transfer_ownership_body.py new file mode 100644 index 0000000..b41d285 --- /dev/null +++ b/omni_python_sdk/models/documents_transfer_ownership_body.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsTransferOwnershipBody") + + +@_attrs_define +class DocumentsTransferOwnershipBody: + """ + Attributes: + user_id (UUID): Membership ID of the new owner + """ + + user_id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + user_id = str(self.user_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "userId": user_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + user_id = UUID(d.pop("userId")) + + documents_transfer_ownership_body = cls( + user_id=user_id, + ) + + documents_transfer_ownership_body.additional_properties = d + return documents_transfer_ownership_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_update_body.py b/omni_python_sdk/models/documents_update_body.py new file mode 100644 index 0000000..a349cd3 --- /dev/null +++ b/omni_python_sdk/models/documents_update_body.py @@ -0,0 +1,101 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsUpdateBody") + + +@_attrs_define +class DocumentsUpdateBody: + """ + Attributes: + clear_existing_draft (bool | Unset): Clear existing draft before updating (for published documents with drafts) + Default: False. + description (None | str | Unset): Document description + identifier (str | Unset): Optional document identifier. If omitted, an identifier is auto-generated. Must be + unique within the organization. + name (str | Unset): New document name + """ + + clear_existing_draft: bool | Unset = False + description: None | str | Unset = UNSET + identifier: str | Unset = UNSET + name: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + clear_existing_draft = self.clear_existing_draft + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + identifier = self.identifier + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if clear_existing_draft is not UNSET: + field_dict["clearExistingDraft"] = clear_existing_draft + if description is not UNSET: + field_dict["description"] = description + if identifier is not UNSET: + field_dict["identifier"] = identifier + if name is not UNSET: + field_dict["name"] = name + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + clear_existing_draft = d.pop("clearExistingDraft", UNSET) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + identifier = d.pop("identifier", UNSET) + + name = d.pop("name", UNSET) + + documents_update_body = cls( + clear_existing_draft=clear_existing_draft, + description=description, + identifier=identifier, + name=name, + ) + + documents_update_body.additional_properties = d + return documents_update_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_update_permission_settings_body.py b/omni_python_sdk/models/documents_update_permission_settings_body.py new file mode 100644 index 0000000..ac65551 --- /dev/null +++ b/omni_python_sdk/models/documents_update_permission_settings_body.py @@ -0,0 +1,154 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.documents_update_permission_settings_body_organization_role import ( + DocumentsUpdatePermissionSettingsBodyOrganizationRole, + check_documents_update_permission_settings_body_organization_role, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsUpdatePermissionSettingsBody") + + +@_attrs_define +class DocumentsUpdatePermissionSettingsBody: + """ + Attributes: + can_download (bool | Unset): Allow downloading + can_drill (bool | Unset): Allow drill-down + can_schedule (bool | Unset): Allow scheduling + can_upload (bool | Unset): Allow uploads + can_use_dashboard_ai (bool | Unset): Allow using dashboard AI + can_use_timezone_override (bool | Unset): Allow timezone override + can_view_workbook (bool | Unset): Allow viewing workbook + organization_access_boost (bool | Unset): Boost organization access + organization_role (DocumentsUpdatePermissionSettingsBodyOrganizationRole | Unset): Organization-wide role for + the document + require_pull_request_to_publish (bool | Unset): Require pull request to publish changes + """ + + can_download: bool | Unset = UNSET + can_drill: bool | Unset = UNSET + can_schedule: bool | Unset = UNSET + can_upload: bool | Unset = UNSET + can_use_dashboard_ai: bool | Unset = UNSET + can_use_timezone_override: bool | Unset = UNSET + can_view_workbook: bool | Unset = UNSET + organization_access_boost: bool | Unset = UNSET + organization_role: DocumentsUpdatePermissionSettingsBodyOrganizationRole | Unset = UNSET + require_pull_request_to_publish: bool | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + can_download = self.can_download + + can_drill = self.can_drill + + can_schedule = self.can_schedule + + can_upload = self.can_upload + + can_use_dashboard_ai = self.can_use_dashboard_ai + + can_use_timezone_override = self.can_use_timezone_override + + can_view_workbook = self.can_view_workbook + + organization_access_boost = self.organization_access_boost + + organization_role: str | Unset = UNSET + if not isinstance(self.organization_role, Unset): + organization_role = self.organization_role + + require_pull_request_to_publish = self.require_pull_request_to_publish + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if can_download is not UNSET: + field_dict["canDownload"] = can_download + if can_drill is not UNSET: + field_dict["canDrill"] = can_drill + if can_schedule is not UNSET: + field_dict["canSchedule"] = can_schedule + if can_upload is not UNSET: + field_dict["canUpload"] = can_upload + if can_use_dashboard_ai is not UNSET: + field_dict["canUseDashboardAi"] = can_use_dashboard_ai + if can_use_timezone_override is not UNSET: + field_dict["canUseTimezoneOverride"] = can_use_timezone_override + if can_view_workbook is not UNSET: + field_dict["canViewWorkbook"] = can_view_workbook + if organization_access_boost is not UNSET: + field_dict["organizationAccessBoost"] = organization_access_boost + if organization_role is not UNSET: + field_dict["organizationRole"] = organization_role + if require_pull_request_to_publish is not UNSET: + field_dict["requirePullRequestToPublish"] = require_pull_request_to_publish + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + can_download = d.pop("canDownload", UNSET) + + can_drill = d.pop("canDrill", UNSET) + + can_schedule = d.pop("canSchedule", UNSET) + + can_upload = d.pop("canUpload", UNSET) + + can_use_dashboard_ai = d.pop("canUseDashboardAi", UNSET) + + can_use_timezone_override = d.pop("canUseTimezoneOverride", UNSET) + + can_view_workbook = d.pop("canViewWorkbook", UNSET) + + organization_access_boost = d.pop("organizationAccessBoost", UNSET) + + _organization_role = d.pop("organizationRole", UNSET) + organization_role: DocumentsUpdatePermissionSettingsBodyOrganizationRole | Unset + if isinstance(_organization_role, Unset): + organization_role = UNSET + else: + organization_role = check_documents_update_permission_settings_body_organization_role(_organization_role) + + require_pull_request_to_publish = d.pop("requirePullRequestToPublish", UNSET) + + documents_update_permission_settings_body = cls( + can_download=can_download, + can_drill=can_drill, + can_schedule=can_schedule, + can_upload=can_upload, + can_use_dashboard_ai=can_use_dashboard_ai, + can_use_timezone_override=can_use_timezone_override, + can_view_workbook=can_view_workbook, + organization_access_boost=organization_access_boost, + organization_role=organization_role, + require_pull_request_to_publish=require_pull_request_to_publish, + ) + + documents_update_permission_settings_body.additional_properties = d + return documents_update_permission_settings_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_update_permission_settings_body_organization_role.py b/omni_python_sdk/models/documents_update_permission_settings_body_organization_role.py new file mode 100644 index 0000000..29c4961 --- /dev/null +++ b/omni_python_sdk/models/documents_update_permission_settings_body_organization_role.py @@ -0,0 +1,22 @@ +from typing import Literal + +DocumentsUpdatePermissionSettingsBodyOrganizationRole = Literal["editor", "manager", "no_access", "viewer"] + +DOCUMENTS_UPDATE_PERMISSION_SETTINGS_BODY_ORGANIZATION_ROLE_VALUES: set[ + DocumentsUpdatePermissionSettingsBodyOrganizationRole +] = { + "editor", + "manager", + "no_access", + "viewer", +} + + +def check_documents_update_permission_settings_body_organization_role( + value: str, +) -> DocumentsUpdatePermissionSettingsBodyOrganizationRole: + if value in DOCUMENTS_UPDATE_PERMISSION_SETTINGS_BODY_ORGANIZATION_ROLE_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {DOCUMENTS_UPDATE_PERMISSION_SETTINGS_BODY_ORGANIZATION_ROLE_VALUES!r}" + ) diff --git a/omni_python_sdk/models/documents_update_permits_body.py b/omni_python_sdk/models/documents_update_permits_body.py new file mode 100644 index 0000000..9cc9d1a --- /dev/null +++ b/omni_python_sdk/models/documents_update_permits_body.py @@ -0,0 +1,114 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.documents_update_permits_body_role import ( + DocumentsUpdatePermitsBodyRole, + check_documents_update_permits_body_role, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsUpdatePermitsBody") + + +@_attrs_define +class DocumentsUpdatePermitsBody: + """ + Attributes: + access_boost (bool | Unset): Access boost setting + role (DocumentsUpdatePermitsBodyRole | Unset): Role to set + user_group_ids (list[str] | Unset): User group IDs to update + user_ids (list[UUID] | Unset): User membership IDs to update + """ + + access_boost: bool | Unset = UNSET + role: DocumentsUpdatePermitsBodyRole | Unset = UNSET + user_group_ids: list[str] | Unset = UNSET + user_ids: list[UUID] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + access_boost = self.access_boost + + role: str | Unset = UNSET + if not isinstance(self.role, Unset): + role = self.role + + user_group_ids: list[str] | Unset = UNSET + if not isinstance(self.user_group_ids, Unset): + user_group_ids = self.user_group_ids + + user_ids: list[str] | Unset = UNSET + if not isinstance(self.user_ids, Unset): + user_ids = [] + for user_ids_item_data in self.user_ids: + user_ids_item = str(user_ids_item_data) + user_ids.append(user_ids_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if access_boost is not UNSET: + field_dict["accessBoost"] = access_boost + if role is not UNSET: + field_dict["role"] = role + if user_group_ids is not UNSET: + field_dict["userGroupIds"] = user_group_ids + if user_ids is not UNSET: + field_dict["userIds"] = user_ids + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + access_boost = d.pop("accessBoost", UNSET) + + _role = d.pop("role", UNSET) + role: DocumentsUpdatePermitsBodyRole | Unset + if isinstance(_role, Unset): + role = UNSET + else: + role = check_documents_update_permits_body_role(_role) + + user_group_ids = cast(list[str], d.pop("userGroupIds", UNSET)) + + _user_ids = d.pop("userIds", UNSET) + user_ids: list[UUID] | Unset = UNSET + if _user_ids is not UNSET: + user_ids = [] + for user_ids_item_data in _user_ids: + user_ids_item = UUID(user_ids_item_data) + + user_ids.append(user_ids_item) + + documents_update_permits_body = cls( + access_boost=access_boost, + role=role, + user_group_ids=user_group_ids, + user_ids=user_ids, + ) + + documents_update_permits_body.additional_properties = d + return documents_update_permits_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_update_permits_body_role.py b/omni_python_sdk/models/documents_update_permits_body_role.py new file mode 100644 index 0000000..a880049 --- /dev/null +++ b/omni_python_sdk/models/documents_update_permits_body_role.py @@ -0,0 +1,17 @@ +from typing import Literal + +DocumentsUpdatePermitsBodyRole = Literal["EDITOR", "EXPLORER", "MANAGER", "NO_ACCESS", "VIEWER"] + +DOCUMENTS_UPDATE_PERMITS_BODY_ROLE_VALUES: set[DocumentsUpdatePermitsBodyRole] = { + "EDITOR", + "EXPLORER", + "MANAGER", + "NO_ACCESS", + "VIEWER", +} + + +def check_documents_update_permits_body_role(value: str) -> DocumentsUpdatePermitsBodyRole: + if value in DOCUMENTS_UPDATE_PERMITS_BODY_ROLE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENTS_UPDATE_PERMITS_BODY_ROLE_VALUES!r}") diff --git a/omni_python_sdk/models/documents_update_response.py b/omni_python_sdk/models/documents_update_response.py new file mode 100644 index 0000000..bc52f77 --- /dev/null +++ b/omni_python_sdk/models/documents_update_response.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsUpdateResponse") + + +@_attrs_define +class DocumentsUpdateResponse: + """ + Attributes: + identifier (str): Document identifier + name (str): Updated document name + description (None | str | Unset): Document description + """ + + identifier: str + name: str + description: None | str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + identifier = self.identifier + + name = self.name + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "identifier": identifier, + "name": name, + } + ) + if description is not UNSET: + field_dict["description"] = description + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + identifier = d.pop("identifier") + + name = d.pop("name") + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + documents_update_response = cls( + identifier=identifier, + name=name, + description=description, + ) + + documents_update_response.additional_properties = d + return documents_update_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_upgrade_layout_body.py b/omni_python_sdk/models/documents_upgrade_layout_body.py new file mode 100644 index 0000000..29ed637 --- /dev/null +++ b/omni_python_sdk/models/documents_upgrade_layout_body.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="DocumentsUpgradeLayoutBody") + + +@_attrs_define +class DocumentsUpgradeLayoutBody: + """ + Attributes: + clear_existing_draft (bool | Unset): When upgrading a published document, discard any existing draft instead of + failing with a conflict. Default: False. + """ + + clear_existing_draft: bool | Unset = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + clear_existing_draft = self.clear_existing_draft + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if clear_existing_draft is not UNSET: + field_dict["clearExistingDraft"] = clear_existing_draft + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + clear_existing_draft = d.pop("clearExistingDraft", UNSET) + + documents_upgrade_layout_body = cls( + clear_existing_draft=clear_existing_draft, + ) + + documents_upgrade_layout_body.additional_properties = d + return documents_upgrade_layout_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_upgrade_layout_response.py b/omni_python_sdk/models/documents_upgrade_layout_response.py new file mode 100644 index 0000000..46785d1 --- /dev/null +++ b/omni_python_sdk/models/documents_upgrade_layout_response.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsUpgradeLayoutResponse") + + +@_attrs_define +class DocumentsUpgradeLayoutResponse: + """ + Attributes: + identifier (str): Document identifier + upgraded (bool): True when the layout was upgraded, false when the document already had advanced layout (no-op). + """ + + identifier: str + upgraded: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + identifier = self.identifier + + upgraded = self.upgraded + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "identifier": identifier, + "upgraded": upgraded, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + identifier = d.pop("identifier") + + upgraded = d.pop("upgraded") + + documents_upgrade_layout_response = cls( + identifier=identifier, + upgraded=upgraded, + ) + + documents_upgrade_layout_response.additional_properties = d + return documents_upgrade_layout_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_v2_create_body.py b/omni_python_sdk/models/documents_v2_create_body.py new file mode 100644 index 0000000..a98a7e2 --- /dev/null +++ b/omni_python_sdk/models/documents_v2_create_body.py @@ -0,0 +1,280 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.controls_patch_external import ControlsPatchExternal + from ..models.grid_container import GridContainer + from ..models.page_container import PageContainer + from ..models.query_presentations_patch_external import QueryPresentationsPatchExternal + from ..models.settings_patch_external import SettingsPatchExternal + from ..models.stack_container import StackContainer + + +T = TypeVar("T", bound="DocumentsV2CreateBody") + + +@_attrs_define +class DocumentsV2CreateBody: + """ + Attributes: + model_id (UUID): Base workbook model the document is built on — a SHARED model, or a SHARED_EXTENSION with + `allowAsWorkbookBase = true`. + name (str): Document name. + containers (list[GridContainer | PageContainer | StackContainer] | None | Unset): Container layout array, or + `null` to create a workbook-only document with no dashboard. When `null`, `controls` and `settings` must be + omitted. + controls (ControlsPatchExternal | Unset): (Not statically modeled; use plain dicts.) + description (None | str | Unset): Document description. + folder_id (None | Unset | UUID): Folder to create the document in. When omitted, defaults to the caller’s + personal "My documents" (requires permission to save personal content — otherwise the request is rejected). + identifier (str | Unset): Optional document identifier. If omitted, an identifier is auto-generated. Must be + unique within the organization. + query_presentations (QueryPresentationsPatchExternal | Unset): (Not statically modeled; use plain dicts.) + settings (SettingsPatchExternal | Unset): Document settings. Shallow-merged with the existing settings. + summary (str | Unset): Optional. Caller-supplied note describing the create, written to the history audit trail. + When omitted, the server auto-fills it with "Created document". + """ + + model_id: UUID + name: str + containers: list[GridContainer | PageContainer | StackContainer] | None | Unset = UNSET + controls: ControlsPatchExternal | Unset = UNSET + description: None | str | Unset = UNSET + folder_id: None | Unset | UUID = UNSET + identifier: str | Unset = UNSET + query_presentations: QueryPresentationsPatchExternal | Unset = UNSET + settings: SettingsPatchExternal | Unset = UNSET + summary: str | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + from ..models.grid_container import GridContainer + from ..models.page_container import PageContainer + + model_id = str(self.model_id) + + name = self.name + + containers: list[dict[str, Any]] | None | Unset + if isinstance(self.containers, Unset): + containers = UNSET + elif isinstance(self.containers, list): + containers = [] + for componentsschemas_containers_on_create_type_0_item_data in self.containers: + componentsschemas_containers_on_create_type_0_item: dict[str, Any] + if isinstance(componentsschemas_containers_on_create_type_0_item_data, GridContainer): + componentsschemas_containers_on_create_type_0_item = ( + componentsschemas_containers_on_create_type_0_item_data.to_dict() + ) + elif isinstance(componentsschemas_containers_on_create_type_0_item_data, PageContainer): + componentsschemas_containers_on_create_type_0_item = ( + componentsschemas_containers_on_create_type_0_item_data.to_dict() + ) + else: + componentsschemas_containers_on_create_type_0_item = ( + componentsschemas_containers_on_create_type_0_item_data.to_dict() + ) + + containers.append(componentsschemas_containers_on_create_type_0_item) + + else: + containers = self.containers + + controls: dict[str, Any] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls.to_dict() + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + folder_id: None | str | Unset + if isinstance(self.folder_id, Unset): + folder_id = UNSET + elif isinstance(self.folder_id, UUID): + folder_id = str(self.folder_id) + else: + folder_id = self.folder_id + + identifier = self.identifier + + query_presentations: dict[str, Any] | Unset = UNSET + if not isinstance(self.query_presentations, Unset): + query_presentations = self.query_presentations.to_dict() + + settings: dict[str, Any] | Unset = UNSET + if not isinstance(self.settings, Unset): + settings = self.settings.to_dict() + + summary = self.summary + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "modelId": model_id, + "name": name, + } + ) + if containers is not UNSET: + field_dict["containers"] = containers + if controls is not UNSET: + field_dict["controls"] = controls + if description is not UNSET: + field_dict["description"] = description + if folder_id is not UNSET: + field_dict["folderId"] = folder_id + if identifier is not UNSET: + field_dict["identifier"] = identifier + if query_presentations is not UNSET: + field_dict["queryPresentations"] = query_presentations + if settings is not UNSET: + field_dict["settings"] = settings + if summary is not UNSET: + field_dict["summary"] = summary + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.controls_patch_external import ControlsPatchExternal + from ..models.grid_container import GridContainer + from ..models.page_container import PageContainer + from ..models.query_presentations_patch_external import QueryPresentationsPatchExternal + from ..models.settings_patch_external import SettingsPatchExternal + from ..models.stack_container import StackContainer + + d = dict(src_dict) + model_id = UUID(d.pop("modelId")) + + name = d.pop("name") + + def _parse_containers(data: object) -> list[GridContainer | PageContainer | StackContainer] | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, list): + raise TypeError() + componentsschemas_containers_on_create_type_0 = [] + _componentsschemas_containers_on_create_type_0 = data + for ( + componentsschemas_containers_on_create_type_0_item_data + ) in _componentsschemas_containers_on_create_type_0: + + def _parse_componentsschemas_containers_on_create_type_0_item( + data: object, + ) -> GridContainer | PageContainer | StackContainer: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_containers_on_create_type_0_item_type_0 = GridContainer.from_dict(data) + + return componentsschemas_containers_on_create_type_0_item_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_containers_on_create_type_0_item_type_1 = PageContainer.from_dict(data) + + return componentsschemas_containers_on_create_type_0_item_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_containers_on_create_type_0_item_type_2 = StackContainer.from_dict(data) + + return componentsschemas_containers_on_create_type_0_item_type_2 + + componentsschemas_containers_on_create_type_0_item = ( + _parse_componentsschemas_containers_on_create_type_0_item( + componentsschemas_containers_on_create_type_0_item_data + ) + ) + + componentsschemas_containers_on_create_type_0.append( + componentsschemas_containers_on_create_type_0_item + ) + + return componentsschemas_containers_on_create_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(list[GridContainer | PageContainer | StackContainer] | None | Unset, data) + + containers = _parse_containers(d.pop("containers", UNSET)) + + _controls = d.pop("controls", UNSET) + controls: ControlsPatchExternal | Unset + if isinstance(_controls, Unset): + controls = UNSET + else: + controls = ControlsPatchExternal.from_dict(_controls) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + def _parse_folder_id(data: object) -> None | Unset | UUID: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + folder_id_type_0 = UUID(data) + + return folder_id_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | Unset | UUID, data) + + folder_id = _parse_folder_id(d.pop("folderId", UNSET)) + + identifier = d.pop("identifier", UNSET) + + _query_presentations = d.pop("queryPresentations", UNSET) + query_presentations: QueryPresentationsPatchExternal | Unset + if isinstance(_query_presentations, Unset): + query_presentations = UNSET + else: + query_presentations = QueryPresentationsPatchExternal.from_dict(_query_presentations) + + _settings = d.pop("settings", UNSET) + settings: SettingsPatchExternal | Unset + if isinstance(_settings, Unset): + settings = UNSET + else: + settings = SettingsPatchExternal.from_dict(_settings) + + summary = d.pop("summary", UNSET) + + documents_v2_create_body = cls( + model_id=model_id, + name=name, + containers=containers, + controls=controls, + description=description, + folder_id=folder_id, + identifier=identifier, + query_presentations=query_presentations, + settings=settings, + summary=summary, + ) + + return documents_v2_create_body diff --git a/omni_python_sdk/models/documents_v2_create_draft_body.py b/omni_python_sdk/models/documents_v2_create_draft_body.py new file mode 100644 index 0000000..a4f3b56 --- /dev/null +++ b/omni_python_sdk/models/documents_v2_create_draft_body.py @@ -0,0 +1,209 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.containers_item import ContainersItem + from ..models.controls_patch_external import ControlsPatchExternal + from ..models.query_presentations_patch_external import QueryPresentationsPatchExternal + from ..models.settings_patch_external import SettingsPatchExternal + + +T = TypeVar("T", bound="DocumentsV2CreateDraftBody") + + +@_attrs_define +class DocumentsV2CreateDraftBody: + """ + Attributes: + containers (list[ContainersItem] | Unset): Container layout array (grid / stack / page / reference containers, + recursively nested). The server validates the full structure on apply. (Not statically modeled; use plain + dicts.) + controls (ControlsPatchExternal | Unset): (Not statically modeled; use plain dicts.) + description (None | str | Unset): + name (str | Unset): Document name. + query_presentations (QueryPresentationsPatchExternal | Unset): (Not statically modeled; use plain dicts.) + settings (SettingsPatchExternal | Unset): Document settings. Shallow-merged with the existing settings. + summary (str | Unset): Optional. Caller-supplied description of what this patch changes, written to the history + audit trail. When omitted, the server auto-generates one from the touched sections. + model_id (UUID | Unset): The document's base model. Immutable and accepted only so a GET response round-trips + through PATCH: a value matching the current model is a no-op, and a differing value is rejected — it cannot re- + base the document. Omit it to leave the model untouched. + branch_id (UUID | Unset): Branch the draft is created on. Omit for a draft on the main (unpublished) workspace. + """ + + containers: list[ContainersItem] | Unset = UNSET + controls: ControlsPatchExternal | Unset = UNSET + description: None | str | Unset = UNSET + name: str | Unset = UNSET + query_presentations: QueryPresentationsPatchExternal | Unset = UNSET + settings: SettingsPatchExternal | Unset = UNSET + summary: str | Unset = UNSET + model_id: UUID | Unset = UNSET + branch_id: UUID | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + containers: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.containers, Unset): + containers = [] + for componentsschemas_containers_item_data in self.containers: + componentsschemas_containers_item = componentsschemas_containers_item_data.to_dict() + containers.append(componentsschemas_containers_item) + + controls: dict[str, Any] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls.to_dict() + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + name = self.name + + query_presentations: dict[str, Any] | Unset = UNSET + if not isinstance(self.query_presentations, Unset): + query_presentations = self.query_presentations.to_dict() + + settings: dict[str, Any] | Unset = UNSET + if not isinstance(self.settings, Unset): + settings = self.settings.to_dict() + + summary = self.summary + + model_id: str | Unset = UNSET + if not isinstance(self.model_id, Unset): + model_id = str(self.model_id) + + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if containers is not UNSET: + field_dict["containers"] = containers + if controls is not UNSET: + field_dict["controls"] = controls + if description is not UNSET: + field_dict["description"] = description + if name is not UNSET: + field_dict["name"] = name + if query_presentations is not UNSET: + field_dict["queryPresentations"] = query_presentations + if settings is not UNSET: + field_dict["settings"] = settings + if summary is not UNSET: + field_dict["summary"] = summary + if model_id is not UNSET: + field_dict["modelId"] = model_id + if branch_id is not UNSET: + field_dict["branchId"] = branch_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.containers_item import ContainersItem + from ..models.controls_patch_external import ControlsPatchExternal + from ..models.query_presentations_patch_external import QueryPresentationsPatchExternal + from ..models.settings_patch_external import SettingsPatchExternal + + d = dict(src_dict) + _containers = d.pop("containers", UNSET) + containers: list[ContainersItem] | Unset = UNSET + if _containers is not UNSET: + containers = [] + for componentsschemas_containers_item_data in _containers: + componentsschemas_containers_item = ContainersItem.from_dict(componentsschemas_containers_item_data) + + containers.append(componentsschemas_containers_item) + + _controls = d.pop("controls", UNSET) + controls: ControlsPatchExternal | Unset + if isinstance(_controls, Unset): + controls = UNSET + else: + controls = ControlsPatchExternal.from_dict(_controls) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + name = d.pop("name", UNSET) + + _query_presentations = d.pop("queryPresentations", UNSET) + query_presentations: QueryPresentationsPatchExternal | Unset + if isinstance(_query_presentations, Unset): + query_presentations = UNSET + else: + query_presentations = QueryPresentationsPatchExternal.from_dict(_query_presentations) + + _settings = d.pop("settings", UNSET) + settings: SettingsPatchExternal | Unset + if isinstance(_settings, Unset): + settings = UNSET + else: + settings = SettingsPatchExternal.from_dict(_settings) + + summary = d.pop("summary", UNSET) + + _model_id = d.pop("modelId", UNSET) + model_id: UUID | Unset + if isinstance(_model_id, Unset): + model_id = UNSET + else: + model_id = UUID(_model_id) + + _branch_id = d.pop("branchId", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + documents_v2_create_draft_body = cls( + containers=containers, + controls=controls, + description=description, + name=name, + query_presentations=query_presentations, + settings=settings, + summary=summary, + model_id=model_id, + branch_id=branch_id, + ) + + documents_v2_create_draft_body.additional_properties = d + return documents_v2_create_draft_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_v2_create_response.py b/omni_python_sdk/models/documents_v2_create_response.py new file mode 100644 index 0000000..4fe474b --- /dev/null +++ b/omni_python_sdk/models/documents_v2_create_response.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsV2CreateResponse") + + +@_attrs_define +class DocumentsV2CreateResponse: + """ + Attributes: + description (None | str): Document description. + identifier (str): Identifier of the newly created document. + name (str): Document name. + """ + + description: None | str + identifier: str + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + description: None | str + description = self.description + + identifier = self.identifier + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "description": description, + "identifier": identifier, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + identifier = d.pop("identifier") + + name = d.pop("name") + + documents_v2_create_response = cls( + description=description, + identifier=identifier, + name=name, + ) + + documents_v2_create_response.additional_properties = d + return documents_v2_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_v2_get_draft_pretty.py b/omni_python_sdk/models/documents_v2_get_draft_pretty.py new file mode 100644 index 0000000..4ccd334 --- /dev/null +++ b/omni_python_sdk/models/documents_v2_get_draft_pretty.py @@ -0,0 +1,16 @@ +from typing import Literal + +DocumentsV2GetDraftPretty = Literal["0", "1", "false", "true"] + +DOCUMENTS_V2_GET_DRAFT_PRETTY_VALUES: set[DocumentsV2GetDraftPretty] = { + "0", + "1", + "false", + "true", +} + + +def check_documents_v2_get_draft_pretty(value: str) -> DocumentsV2GetDraftPretty: + if value in DOCUMENTS_V2_GET_DRAFT_PRETTY_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENTS_V2_GET_DRAFT_PRETTY_VALUES!r}") diff --git a/omni_python_sdk/models/documents_v2_get_pretty.py b/omni_python_sdk/models/documents_v2_get_pretty.py new file mode 100644 index 0000000..547f7f9 --- /dev/null +++ b/omni_python_sdk/models/documents_v2_get_pretty.py @@ -0,0 +1,16 @@ +from typing import Literal + +DocumentsV2GetPretty = Literal["0", "1", "false", "true"] + +DOCUMENTS_V2_GET_PRETTY_VALUES: set[DocumentsV2GetPretty] = { + "0", + "1", + "false", + "true", +} + + +def check_documents_v2_get_pretty(value: str) -> DocumentsV2GetPretty: + if value in DOCUMENTS_V2_GET_PRETTY_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {DOCUMENTS_V2_GET_PRETTY_VALUES!r}") diff --git a/omni_python_sdk/models/documents_v2_patch_draft_body.py b/omni_python_sdk/models/documents_v2_patch_draft_body.py new file mode 100644 index 0000000..15b31ac --- /dev/null +++ b/omni_python_sdk/models/documents_v2_patch_draft_body.py @@ -0,0 +1,174 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.containers_item import ContainersItem + from ..models.controls_patch_external import ControlsPatchExternal + from ..models.query_presentations_patch_external import QueryPresentationsPatchExternal + from ..models.settings_patch_external import SettingsPatchExternal + + +T = TypeVar("T", bound="DocumentsV2PatchDraftBody") + + +@_attrs_define +class DocumentsV2PatchDraftBody: + """ + Attributes: + containers (list[ContainersItem] | Unset): Container layout array (grid / stack / page / reference containers, + recursively nested). The server validates the full structure on apply. (Not statically modeled; use plain + dicts.) + controls (ControlsPatchExternal | Unset): (Not statically modeled; use plain dicts.) + description (None | str | Unset): + name (str | Unset): Document name. + query_presentations (QueryPresentationsPatchExternal | Unset): (Not statically modeled; use plain dicts.) + settings (SettingsPatchExternal | Unset): Document settings. Shallow-merged with the existing settings. + summary (str | Unset): Optional. Caller-supplied description of what this patch changes, written to the history + audit trail. When omitted, the server auto-generates one from the touched sections. + model_id (UUID | Unset): The document's base model. Immutable and accepted only so a GET response round-trips + through PATCH: a value matching the current model is a no-op, and a differing value is rejected — it cannot re- + base the document. Omit it to leave the model untouched. + """ + + containers: list[ContainersItem] | Unset = UNSET + controls: ControlsPatchExternal | Unset = UNSET + description: None | str | Unset = UNSET + name: str | Unset = UNSET + query_presentations: QueryPresentationsPatchExternal | Unset = UNSET + settings: SettingsPatchExternal | Unset = UNSET + summary: str | Unset = UNSET + model_id: UUID | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + containers: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.containers, Unset): + containers = [] + for componentsschemas_containers_item_data in self.containers: + componentsschemas_containers_item = componentsschemas_containers_item_data.to_dict() + containers.append(componentsschemas_containers_item) + + controls: dict[str, Any] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls.to_dict() + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + name = self.name + + query_presentations: dict[str, Any] | Unset = UNSET + if not isinstance(self.query_presentations, Unset): + query_presentations = self.query_presentations.to_dict() + + settings: dict[str, Any] | Unset = UNSET + if not isinstance(self.settings, Unset): + settings = self.settings.to_dict() + + summary = self.summary + + model_id: str | Unset = UNSET + if not isinstance(self.model_id, Unset): + model_id = str(self.model_id) + + field_dict: dict[str, Any] = {} + + field_dict.update({}) + if containers is not UNSET: + field_dict["containers"] = containers + if controls is not UNSET: + field_dict["controls"] = controls + if description is not UNSET: + field_dict["description"] = description + if name is not UNSET: + field_dict["name"] = name + if query_presentations is not UNSET: + field_dict["queryPresentations"] = query_presentations + if settings is not UNSET: + field_dict["settings"] = settings + if summary is not UNSET: + field_dict["summary"] = summary + if model_id is not UNSET: + field_dict["modelId"] = model_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.containers_item import ContainersItem + from ..models.controls_patch_external import ControlsPatchExternal + from ..models.query_presentations_patch_external import QueryPresentationsPatchExternal + from ..models.settings_patch_external import SettingsPatchExternal + + d = dict(src_dict) + _containers = d.pop("containers", UNSET) + containers: list[ContainersItem] | Unset = UNSET + if _containers is not UNSET: + containers = [] + for componentsschemas_containers_item_data in _containers: + componentsschemas_containers_item = ContainersItem.from_dict(componentsschemas_containers_item_data) + + containers.append(componentsschemas_containers_item) + + _controls = d.pop("controls", UNSET) + controls: ControlsPatchExternal | Unset + if isinstance(_controls, Unset): + controls = UNSET + else: + controls = ControlsPatchExternal.from_dict(_controls) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + name = d.pop("name", UNSET) + + _query_presentations = d.pop("queryPresentations", UNSET) + query_presentations: QueryPresentationsPatchExternal | Unset + if isinstance(_query_presentations, Unset): + query_presentations = UNSET + else: + query_presentations = QueryPresentationsPatchExternal.from_dict(_query_presentations) + + _settings = d.pop("settings", UNSET) + settings: SettingsPatchExternal | Unset + if isinstance(_settings, Unset): + settings = UNSET + else: + settings = SettingsPatchExternal.from_dict(_settings) + + summary = d.pop("summary", UNSET) + + _model_id = d.pop("modelId", UNSET) + model_id: UUID | Unset + if isinstance(_model_id, Unset): + model_id = UNSET + else: + model_id = UUID(_model_id) + + documents_v2_patch_draft_body = cls( + containers=containers, + controls=controls, + description=description, + name=name, + query_presentations=query_presentations, + settings=settings, + summary=summary, + model_id=model_id, + ) + + return documents_v2_patch_draft_body diff --git a/omni_python_sdk/models/documents_v2_patch_draft_response.py b/omni_python_sdk/models/documents_v2_patch_draft_response.py new file mode 100644 index 0000000..85cfd23 --- /dev/null +++ b/omni_python_sdk/models/documents_v2_patch_draft_response.py @@ -0,0 +1,92 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsV2PatchDraftResponse") + + +@_attrs_define +class DocumentsV2PatchDraftResponse: + """ + Attributes: + description (None | str): Document description. + draft_identifier (str): Identifier of the draft the patch was applied to. + identifier (str): Published document identifier the draft targets. + name (str): Document name. + """ + + description: None | str + draft_identifier: str + identifier: str + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + description: None | str + description = self.description + + draft_identifier = self.draft_identifier + + identifier = self.identifier + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "description": description, + "draftIdentifier": draft_identifier, + "identifier": identifier, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + draft_identifier = d.pop("draftIdentifier") + + identifier = d.pop("identifier") + + name = d.pop("name") + + documents_v2_patch_draft_response = cls( + description=description, + draft_identifier=draft_identifier, + identifier=identifier, + name=name, + ) + + documents_v2_patch_draft_response.additional_properties = d + return documents_v2_patch_draft_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_v2_publish_draft_response.py b/omni_python_sdk/models/documents_v2_publish_draft_response.py new file mode 100644 index 0000000..dc2e91b --- /dev/null +++ b/omni_python_sdk/models/documents_v2_publish_draft_response.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsV2PublishDraftResponse") + + +@_attrs_define +class DocumentsV2PublishDraftResponse: + """ + Attributes: + description (None | str): Document description. + identifier (str): Published document identifier. + name (str): Document name. + """ + + description: None | str + identifier: str + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + description: None | str + description = self.description + + identifier = self.identifier + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "description": description, + "identifier": identifier, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + identifier = d.pop("identifier") + + name = d.pop("name") + + documents_v2_publish_draft_response = cls( + description=description, + identifier=identifier, + name=name, + ) + + documents_v2_publish_draft_response.additional_properties = d + return documents_v2_publish_draft_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_v2_read_response.py b/omni_python_sdk/models/documents_v2_read_response.py new file mode 100644 index 0000000..a06f30b --- /dev/null +++ b/omni_python_sdk/models/documents_v2_read_response.py @@ -0,0 +1,163 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.containers_item import ContainersItem + from ..models.controls_read_external import ControlsReadExternal + from ..models.query_presentations_read_external import QueryPresentationsReadExternal + from ..models.settings_read_external import SettingsReadExternal + + +T = TypeVar("T", bound="DocumentsV2ReadResponse") + + +@_attrs_define +class DocumentsV2ReadResponse: + """ + Attributes: + description (None | str): Document description. + model_id (UUID): Base model the document is built on (the `modelId` supplied at create). Immutable — echoed here + so a GET round-trips through PATCH; supplying a different value on PATCH is rejected. + name (str): Document name. + query_presentations (QueryPresentationsReadExternal): (Not statically modeled; use plain dicts.) + containers (list[ContainersItem] | Unset): Container layout array (grid / stack / page / reference containers, + recursively nested). The server validates the full structure on apply. (Not statically modeled; use plain + dicts.) + controls (ControlsReadExternal | Unset): (Not statically modeled; use plain dicts.) + settings (SettingsReadExternal | Unset): + """ + + description: None | str + model_id: UUID + name: str + query_presentations: QueryPresentationsReadExternal + containers: list[ContainersItem] | Unset = UNSET + controls: ControlsReadExternal | Unset = UNSET + settings: SettingsReadExternal | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + description: None | str + description = self.description + + model_id = str(self.model_id) + + name = self.name + + query_presentations = self.query_presentations.to_dict() + + containers: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.containers, Unset): + containers = [] + for componentsschemas_containers_item_data in self.containers: + componentsschemas_containers_item = componentsschemas_containers_item_data.to_dict() + containers.append(componentsschemas_containers_item) + + controls: dict[str, Any] | Unset = UNSET + if not isinstance(self.controls, Unset): + controls = self.controls.to_dict() + + settings: dict[str, Any] | Unset = UNSET + if not isinstance(self.settings, Unset): + settings = self.settings.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "description": description, + "modelId": model_id, + "name": name, + "queryPresentations": query_presentations, + } + ) + if containers is not UNSET: + field_dict["containers"] = containers + if controls is not UNSET: + field_dict["controls"] = controls + if settings is not UNSET: + field_dict["settings"] = settings + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.containers_item import ContainersItem + from ..models.controls_read_external import ControlsReadExternal + from ..models.query_presentations_read_external import QueryPresentationsReadExternal + from ..models.settings_read_external import SettingsReadExternal + + d = dict(src_dict) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + model_id = UUID(d.pop("modelId")) + + name = d.pop("name") + + query_presentations = QueryPresentationsReadExternal.from_dict(d.pop("queryPresentations")) + + _containers = d.pop("containers", UNSET) + containers: list[ContainersItem] | Unset = UNSET + if _containers is not UNSET: + containers = [] + for componentsschemas_containers_item_data in _containers: + componentsschemas_containers_item = ContainersItem.from_dict(componentsschemas_containers_item_data) + + containers.append(componentsschemas_containers_item) + + _controls = d.pop("controls", UNSET) + controls: ControlsReadExternal | Unset + if isinstance(_controls, Unset): + controls = UNSET + else: + controls = ControlsReadExternal.from_dict(_controls) + + _settings = d.pop("settings", UNSET) + settings: SettingsReadExternal | Unset + if isinstance(_settings, Unset): + settings = UNSET + else: + settings = SettingsReadExternal.from_dict(_settings) + + documents_v2_read_response = cls( + description=description, + model_id=model_id, + name=name, + query_presentations=query_presentations, + containers=containers, + controls=controls, + settings=settings, + ) + + documents_v2_read_response.additional_properties = d + return documents_v2_read_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_v2_update_identifier_body.py b/omni_python_sdk/models/documents_v2_update_identifier_body.py new file mode 100644 index 0000000..3d88ce1 --- /dev/null +++ b/omni_python_sdk/models/documents_v2_update_identifier_body.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define + +T = TypeVar("T", bound="DocumentsV2UpdateIdentifierBody") + + +@_attrs_define +class DocumentsV2UpdateIdentifierBody: + """ + Attributes: + identifier (str): Optional document identifier. If omitted, an identifier is auto-generated. Must be unique + within the organization. + """ + + identifier: str + + def to_dict(self) -> dict[str, Any]: + identifier = self.identifier + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "identifier": identifier, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + identifier = d.pop("identifier") + + documents_v2_update_identifier_body = cls( + identifier=identifier, + ) + + return documents_v2_update_identifier_body diff --git a/omni_python_sdk/models/documents_v2_update_identifier_response.py b/omni_python_sdk/models/documents_v2_update_identifier_response.py new file mode 100644 index 0000000..34bc026 --- /dev/null +++ b/omni_python_sdk/models/documents_v2_update_identifier_response.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentsV2UpdateIdentifierResponse") + + +@_attrs_define +class DocumentsV2UpdateIdentifierResponse: + """ + Attributes: + description (None | str): Document description. + identifier (str): The document identifier after the rename. + name (str): Document name. + """ + + description: None | str + identifier: str + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + description: None | str + description = self.description + + identifier = self.identifier + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "description": description, + "identifier": identifier, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + identifier = d.pop("identifier") + + name = d.pop("name") + + documents_v2_update_identifier_response = cls( + description=description, + identifier=identifier, + name=name, + ) + + documents_v2_update_identifier_response.additional_properties = d + return documents_v2_update_identifier_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/email_recipient.py b/omni_python_sdk/models/email_recipient.py new file mode 100644 index 0000000..26ed91e --- /dev/null +++ b/omni_python_sdk/models/email_recipient.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EmailRecipient") + + +@_attrs_define +class EmailRecipient: + """ + Attributes: + email (str): Recipient's email address. Example: user@example.com. + id (str): Unique identifier for the recipient. + name (str): Recipient's display name. Example: John Doe. + """ + + email: str + id: str + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + email = self.email + + id = self.id + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "email": email, + "id": id, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + email = d.pop("email") + + id = d.pop("id") + + name = d.pop("name") + + email_recipient = cls( + email=email, + id=id, + name=name, + ) + + email_recipient.additional_properties = d + return email_recipient + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/embed_sso_generate_session_body.py b/omni_python_sdk/models/embed_sso_generate_session_body.py new file mode 100644 index 0000000..6ffb3bf --- /dev/null +++ b/omni_python_sdk/models/embed_sso_generate_session_body.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.embed_sso_generate_session_body_user_attributes import EmbedSsoGenerateSessionBodyUserAttributes + + +T = TypeVar("T", bound="EmbedSsoGenerateSessionBody") + + +@_attrs_define +class EmbedSsoGenerateSessionBody: + """ + Attributes: + external_id (str): External identifier for the user (from your system) Example: user-123. + name (str): Display name for the user Example: John Doe. + groups (list[str] | Unset): Optional list of non-entity group names to assign to the user. Entity-group + membership is managed by the entity parameter. Example: ['engineering', 'sales']. + user_attributes (EmbedSsoGenerateSessionBodyUserAttributes | Unset): Optional user attributes for row-level + security + """ + + external_id: str + name: str + groups: list[str] | Unset = UNSET + user_attributes: EmbedSsoGenerateSessionBodyUserAttributes | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + external_id = self.external_id + + name = self.name + + groups: list[str] | Unset = UNSET + if not isinstance(self.groups, Unset): + groups = self.groups + + user_attributes: dict[str, Any] | Unset = UNSET + if not isinstance(self.user_attributes, Unset): + user_attributes = self.user_attributes.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "externalId": external_id, + "name": name, + } + ) + if groups is not UNSET: + field_dict["groups"] = groups + if user_attributes is not UNSET: + field_dict["userAttributes"] = user_attributes + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.embed_sso_generate_session_body_user_attributes import EmbedSsoGenerateSessionBodyUserAttributes + + d = dict(src_dict) + external_id = d.pop("externalId") + + name = d.pop("name") + + groups = cast(list[str], d.pop("groups", UNSET)) + + _user_attributes = d.pop("userAttributes", UNSET) + user_attributes: EmbedSsoGenerateSessionBodyUserAttributes | Unset + if isinstance(_user_attributes, Unset): + user_attributes = UNSET + else: + user_attributes = EmbedSsoGenerateSessionBodyUserAttributes.from_dict(_user_attributes) + + embed_sso_generate_session_body = cls( + external_id=external_id, + name=name, + groups=groups, + user_attributes=user_attributes, + ) + + embed_sso_generate_session_body.additional_properties = d + return embed_sso_generate_session_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/embed_sso_generate_session_body_user_attributes.py b/omni_python_sdk/models/embed_sso_generate_session_body_user_attributes.py new file mode 100644 index 0000000..1e71dae --- /dev/null +++ b/omni_python_sdk/models/embed_sso_generate_session_body_user_attributes.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EmbedSsoGenerateSessionBodyUserAttributes") + + +@_attrs_define +class EmbedSsoGenerateSessionBodyUserAttributes: + """Optional user attributes for row-level security""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + embed_sso_generate_session_body_user_attributes = cls() + + embed_sso_generate_session_body_user_attributes.additional_properties = d + return embed_sso_generate_session_body_user_attributes + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/embed_sso_generate_session_response.py b/omni_python_sdk/models/embed_sso_generate_session_response.py new file mode 100644 index 0000000..059383c --- /dev/null +++ b/omni_python_sdk/models/embed_sso_generate_session_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EmbedSsoGenerateSessionResponse") + + +@_attrs_define +class EmbedSsoGenerateSessionResponse: + """ + Attributes: + session_id (str): Session ID to use for embedding Omni content + """ + + session_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + session_id = self.session_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "sessionId": session_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + session_id = d.pop("sessionId") + + embed_sso_generate_session_response = cls( + session_id=session_id, + ) + + embed_sso_generate_session_response.additional_properties = d + return embed_sso_generate_session_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_api_error_400.py b/omni_python_sdk/models/eval_api_error_400.py new file mode 100644 index 0000000..8c30773 --- /dev/null +++ b/omni_python_sdk/models/eval_api_error_400.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalApiError400") + + +@_attrs_define +class EvalApiError400: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: Bad Request: name: Required. + status (int): HTTP status code of the error. Example: 400. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + eval_api_error_400 = cls( + detail=detail, + status=status, + ) + + eval_api_error_400.additional_properties = d + return eval_api_error_400 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_api_error_401.py b/omni_python_sdk/models/eval_api_error_401.py new file mode 100644 index 0000000..33fb273 --- /dev/null +++ b/omni_python_sdk/models/eval_api_error_401.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalApiError401") + + +@_attrs_define +class EvalApiError401: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: Unauthorized: Missing or invalid + API key. + status (int): HTTP status code of the error. Example: 401. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + eval_api_error_401 = cls( + detail=detail, + status=status, + ) + + eval_api_error_401.additional_properties = d + return eval_api_error_401 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_api_error_403.py b/omni_python_sdk/models/eval_api_error_403.py new file mode 100644 index 0000000..87beb1d --- /dev/null +++ b/omni_python_sdk/models/eval_api_error_403.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalApiError403") + + +@_attrs_define +class EvalApiError403: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: AI eval requires at least + Querier access on the model. + status (int): HTTP status code of the error. Example: 403. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + eval_api_error_403 = cls( + detail=detail, + status=status, + ) + + eval_api_error_403.additional_properties = d + return eval_api_error_403 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_api_error_404.py b/omni_python_sdk/models/eval_api_error_404.py new file mode 100644 index 0000000..99be112 --- /dev/null +++ b/omni_python_sdk/models/eval_api_error_404.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalApiError404") + + +@_attrs_define +class EvalApiError404: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: Prompt set not found. + status (int): HTTP status code of the error. Example: 404. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + eval_api_error_404 = cls( + detail=detail, + status=status, + ) + + eval_api_error_404.additional_properties = d + return eval_api_error_404 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_api_error_422.py b/omni_python_sdk/models/eval_api_error_422.py new file mode 100644 index 0000000..0404093 --- /dev/null +++ b/omni_python_sdk/models/eval_api_error_422.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalApiError422") + + +@_attrs_define +class EvalApiError422: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: A prompt being updated does not + belong to this prompt set. + status (int): HTTP status code of the error. Example: 422. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + eval_api_error_422 = cls( + detail=detail, + status=status, + ) + + eval_api_error_422.additional_properties = d + return eval_api_error_422 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_api_error_429.py b/omni_python_sdk/models/eval_api_error_429.py new file mode 100644 index 0000000..f89ddce --- /dev/null +++ b/omni_python_sdk/models/eval_api_error_429.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalApiError429") + + +@_attrs_define +class EvalApiError429: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: Too many active runs; wait for + an in-flight run to finish. + status (int): HTTP status code of the error. Example: 429. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + eval_api_error_429 = cls( + detail=detail, + status=status, + ) + + eval_api_error_429.additional_properties = d + return eval_api_error_429 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_api_error_500.py b/omni_python_sdk/models/eval_api_error_500.py new file mode 100644 index 0000000..73402f8 --- /dev/null +++ b/omni_python_sdk/models/eval_api_error_500.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalApiError500") + + +@_attrs_define +class EvalApiError500: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: Archive committed but a run- + cancellation failed; retry to complete. + status (int): HTTP status code of the error. Example: 500. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + eval_api_error_500 = cls( + detail=detail, + status=status, + ) + + eval_api_error_500.additional_properties = d + return eval_api_error_500 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_api_error_503.py b/omni_python_sdk/models/eval_api_error_503.py new file mode 100644 index 0000000..8a2540a --- /dev/null +++ b/omni_python_sdk/models/eval_api_error_503.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalApiError503") + + +@_attrs_define +class EvalApiError503: + """ + Attributes: + detail (str): Human-readable error message describing what went wrong. Example: AI eval is paused for this + organization. + status (int): HTTP status code of the error. Example: 503. + """ + + detail: str + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + status = d.pop("status") + + eval_api_error_503 = cls( + detail=detail, + status=status, + ) + + eval_api_error_503.additional_properties = d + return eval_api_error_503 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt.py b/omni_python_sdk/models/eval_prompt.py new file mode 100644 index 0000000..0573d68 --- /dev/null +++ b/omni_python_sdk/models/eval_prompt.py @@ -0,0 +1,115 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalPrompt") + + +@_attrs_define +class EvalPrompt: + """ + Attributes: + created_at (None | str): ISO 8601 timestamp when the prompt was created. Example: 2025-01-15T10:00:00.000Z. + expectation (None | str): The expectation the analysis judge scores the analysis against, or null when none was + set. Example: The top product by revenue should be Aniseed Syrup.. + id (UUID): Unique identifier for the prompt. Example: 770e8400-e29b-41d4-a716-446655440002. + prompt_text (str): The natural language prompt text the AI is evaluated on. Example: What are the top 5 products + by revenue?. + updated_at (None | str): ISO 8601 timestamp when the prompt was last updated. Example: 2025-01-15T10:00:00.000Z. + """ + + created_at: None | str + expectation: None | str + id: UUID + prompt_text: str + updated_at: None | str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created_at: None | str + created_at = self.created_at + + expectation: None | str + expectation = self.expectation + + id = str(self.id) + + prompt_text = self.prompt_text + + updated_at: None | str + updated_at = self.updated_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "created_at": created_at, + "expectation": expectation, + "id": id, + "prompt_text": prompt_text, + "updated_at": updated_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_created_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + created_at = _parse_created_at(d.pop("created_at")) + + def _parse_expectation(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + expectation = _parse_expectation(d.pop("expectation")) + + id = UUID(d.pop("id")) + + prompt_text = d.pop("prompt_text") + + def _parse_updated_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + updated_at = _parse_updated_at(d.pop("updated_at")) + + eval_prompt = cls( + created_at=created_at, + expectation=expectation, + id=id, + prompt_text=prompt_text, + updated_at=updated_at, + ) + + eval_prompt.additional_properties = d + return eval_prompt + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt_set.py b/omni_python_sdk/models/eval_prompt_set.py new file mode 100644 index 0000000..4dd293f --- /dev/null +++ b/omni_python_sdk/models/eval_prompt_set.py @@ -0,0 +1,161 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.eval_prompt import EvalPrompt + + +T = TypeVar("T", bound="EvalPromptSet") + + +@_attrs_define +class EvalPromptSet: + """ + Attributes: + created_at (None | str): ISO 8601 timestamp when the prompt set was created. Example: 2025-01-15T10:00:00.000Z. + description (None | str): Optional human-readable description of the prompt set. Example: Regression suite for + the orders topic. + id (UUID): Unique identifier for the prompt set. Example: 550e8400-e29b-41d4-a716-446655440000. + is_archived (bool): Whether the prompt set has been archived. + model_id (UUID): The shared model this prompt set is bound to. Example: 880e8400-e29b-41d4-a716-446655440003. + name (str): Human-readable name for the prompt set. Example: Orders regression. + prompts (list[EvalPrompt]): Prompts that make up the set. + slug (str): URL-safe identifier for the prompt set. Unique per `model_id`. Example: orders-regression. + updated_at (None | str): ISO 8601 timestamp when the prompt set was last updated. Example: + 2025-01-15T10:00:00.000Z. + """ + + created_at: None | str + description: None | str + id: UUID + is_archived: bool + model_id: UUID + name: str + prompts: list[EvalPrompt] + slug: str + updated_at: None | str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created_at: None | str + created_at = self.created_at + + description: None | str + description = self.description + + id = str(self.id) + + is_archived = self.is_archived + + model_id = str(self.model_id) + + name = self.name + + prompts = [] + for prompts_item_data in self.prompts: + prompts_item = prompts_item_data.to_dict() + prompts.append(prompts_item) + + slug = self.slug + + updated_at: None | str + updated_at = self.updated_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "created_at": created_at, + "description": description, + "id": id, + "is_archived": is_archived, + "model_id": model_id, + "name": name, + "prompts": prompts, + "slug": slug, + "updated_at": updated_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_prompt import EvalPrompt + + d = dict(src_dict) + + def _parse_created_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + created_at = _parse_created_at(d.pop("created_at")) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + id = UUID(d.pop("id")) + + is_archived = d.pop("is_archived") + + model_id = UUID(d.pop("model_id")) + + name = d.pop("name") + + prompts = [] + _prompts = d.pop("prompts") + for prompts_item_data in _prompts: + prompts_item = EvalPrompt.from_dict(prompts_item_data) + + prompts.append(prompts_item) + + slug = d.pop("slug") + + def _parse_updated_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + updated_at = _parse_updated_at(d.pop("updated_at")) + + eval_prompt_set = cls( + created_at=created_at, + description=description, + id=id, + is_archived=is_archived, + model_id=model_id, + name=name, + prompts=prompts, + slug=slug, + updated_at=updated_at, + ) + + eval_prompt_set.additional_properties = d + return eval_prompt_set + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt_set_list_item.py b/omni_python_sdk/models/eval_prompt_set_list_item.py new file mode 100644 index 0000000..f1d2a98 --- /dev/null +++ b/omni_python_sdk/models/eval_prompt_set_list_item.py @@ -0,0 +1,162 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalPromptSetListItem") + + +@_attrs_define +class EvalPromptSetListItem: + """ + Attributes: + created_at (None | str): ISO 8601 timestamp when the prompt set was created. Example: 2025-01-15T10:00:00.000Z. + description (None | str): Optional human-readable description of the prompt set. Example: Regression suite for + the orders topic. + id (UUID): Unique identifier for the prompt set. Example: 550e8400-e29b-41d4-a716-446655440000. + is_archived (bool): Whether the prompt set has been archived. + model_id (UUID): The shared model this prompt set is bound to. Example: 880e8400-e29b-41d4-a716-446655440003. + name (str): Human-readable name for the prompt set. Example: Orders regression. + slug (str): URL-safe identifier for the prompt set. Unique per `model_id`. Example: orders-regression. + updated_at (None | str): ISO 8601 timestamp when the prompt set was last updated. Example: + 2025-01-15T10:00:00.000Z. + latest_run_at (None | str): ISO 8601 timestamp of the most recent run on this prompt set, if any. Example: + 2025-01-15T10:05:00.000Z. + prompt_count (int): Number of prompts in the set. Example: 12. + """ + + created_at: None | str + description: None | str + id: UUID + is_archived: bool + model_id: UUID + name: str + slug: str + updated_at: None | str + latest_run_at: None | str + prompt_count: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created_at: None | str + created_at = self.created_at + + description: None | str + description = self.description + + id = str(self.id) + + is_archived = self.is_archived + + model_id = str(self.model_id) + + name = self.name + + slug = self.slug + + updated_at: None | str + updated_at = self.updated_at + + latest_run_at: None | str + latest_run_at = self.latest_run_at + + prompt_count = self.prompt_count + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "created_at": created_at, + "description": description, + "id": id, + "is_archived": is_archived, + "model_id": model_id, + "name": name, + "slug": slug, + "updated_at": updated_at, + "latest_run_at": latest_run_at, + "prompt_count": prompt_count, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_created_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + created_at = _parse_created_at(d.pop("created_at")) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + id = UUID(d.pop("id")) + + is_archived = d.pop("is_archived") + + model_id = UUID(d.pop("model_id")) + + name = d.pop("name") + + slug = d.pop("slug") + + def _parse_updated_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + updated_at = _parse_updated_at(d.pop("updated_at")) + + def _parse_latest_run_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + latest_run_at = _parse_latest_run_at(d.pop("latest_run_at")) + + prompt_count = d.pop("prompt_count") + + eval_prompt_set_list_item = cls( + created_at=created_at, + description=description, + id=id, + is_archived=is_archived, + model_id=model_id, + name=name, + slug=slug, + updated_at=updated_at, + latest_run_at=latest_run_at, + prompt_count=prompt_count, + ) + + eval_prompt_set_list_item.additional_properties = d + return eval_prompt_set_list_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt_sets_create_body.py b/omni_python_sdk/models/eval_prompt_sets_create_body.py new file mode 100644 index 0000000..10023f4 --- /dev/null +++ b/omni_python_sdk/models/eval_prompt_sets_create_body.py @@ -0,0 +1,130 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.eval_prompt_sets_create_body_prompts_item import EvalPromptSetsCreateBodyPromptsItem + + +T = TypeVar("T", bound="EvalPromptSetsCreateBody") + + +@_attrs_define +class EvalPromptSetsCreateBody: + """ + Attributes: + model_id (UUID): The shared model this prompt set is bound to. Example: 880e8400-e29b-41d4-a716-446655440003. + name (str): Human-readable name for the prompt set. 255 characters or fewer. Example: Orders regression. + slug (str): URL-safe identifier for the prompt set. Must be unique per `model_id` and match `^[a-z][a-z0-9-]*$`. + Max 255 characters. Example: orders-regression. + description (None | str | Unset): Optional human-readable description of the prompt set. Max 1024 characters. + Example: Regression suite for the orders topic. + prompts (list[EvalPromptSetsCreateBodyPromptsItem] | Unset): Initial prompts for the set. Defaults to an empty + list. At most 25 prompts. + """ + + model_id: UUID + name: str + slug: str + description: None | str | Unset = UNSET + prompts: list[EvalPromptSetsCreateBodyPromptsItem] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + model_id = str(self.model_id) + + name = self.name + + slug = self.slug + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + prompts: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.prompts, Unset): + prompts = [] + for prompts_item_data in self.prompts: + prompts_item = prompts_item_data.to_dict() + prompts.append(prompts_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "model_id": model_id, + "name": name, + "slug": slug, + } + ) + if description is not UNSET: + field_dict["description"] = description + if prompts is not UNSET: + field_dict["prompts"] = prompts + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_prompt_sets_create_body_prompts_item import EvalPromptSetsCreateBodyPromptsItem + + d = dict(src_dict) + model_id = UUID(d.pop("model_id")) + + name = d.pop("name") + + slug = d.pop("slug") + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + _prompts = d.pop("prompts", UNSET) + prompts: list[EvalPromptSetsCreateBodyPromptsItem] | Unset = UNSET + if _prompts is not UNSET: + prompts = [] + for prompts_item_data in _prompts: + prompts_item = EvalPromptSetsCreateBodyPromptsItem.from_dict(prompts_item_data) + + prompts.append(prompts_item) + + eval_prompt_sets_create_body = cls( + model_id=model_id, + name=name, + slug=slug, + description=description, + prompts=prompts, + ) + + eval_prompt_sets_create_body.additional_properties = d + return eval_prompt_sets_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt_sets_create_body_prompts_item.py b/omni_python_sdk/models/eval_prompt_sets_create_body_prompts_item.py new file mode 100644 index 0000000..f25b278 --- /dev/null +++ b/omni_python_sdk/models/eval_prompt_sets_create_body_prompts_item.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="EvalPromptSetsCreateBodyPromptsItem") + + +@_attrs_define +class EvalPromptSetsCreateBodyPromptsItem: + """ + Attributes: + prompt_text (str): The natural language prompt text. Max 8000 characters. Example: What are the top 5 products + by revenue?. + expectation (None | str | Unset): Optional expectation the analysis judge scores the analysis against. Max 16000 + characters. Example: The top product by revenue should be Aniseed Syrup.. + """ + + prompt_text: str + expectation: None | str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + prompt_text = self.prompt_text + + expectation: None | str | Unset + if isinstance(self.expectation, Unset): + expectation = UNSET + else: + expectation = self.expectation + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "prompt_text": prompt_text, + } + ) + if expectation is not UNSET: + field_dict["expectation"] = expectation + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + prompt_text = d.pop("prompt_text") + + def _parse_expectation(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + expectation = _parse_expectation(d.pop("expectation", UNSET)) + + eval_prompt_sets_create_body_prompts_item = cls( + prompt_text=prompt_text, + expectation=expectation, + ) + + eval_prompt_sets_create_body_prompts_item.additional_properties = d + return eval_prompt_sets_create_body_prompts_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt_sets_create_response.py b/omni_python_sdk/models/eval_prompt_sets_create_response.py new file mode 100644 index 0000000..9be1866 --- /dev/null +++ b/omni_python_sdk/models/eval_prompt_sets_create_response.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.eval_prompt_set import EvalPromptSet + + +T = TypeVar("T", bound="EvalPromptSetsCreateResponse") + + +@_attrs_define +class EvalPromptSetsCreateResponse: + """ + Attributes: + prompt_set (EvalPromptSet): + """ + + prompt_set: EvalPromptSet + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + prompt_set = self.prompt_set.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "prompt_set": prompt_set, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_prompt_set import EvalPromptSet + + d = dict(src_dict) + prompt_set = EvalPromptSet.from_dict(d.pop("prompt_set")) + + eval_prompt_sets_create_response = cls( + prompt_set=prompt_set, + ) + + eval_prompt_sets_create_response.additional_properties = d + return eval_prompt_sets_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt_sets_delete_response.py b/omni_python_sdk/models/eval_prompt_sets_delete_response.py new file mode 100644 index 0000000..4c0f7ad --- /dev/null +++ b/omni_python_sdk/models/eval_prompt_sets_delete_response.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalPromptSetsDeleteResponse") + + +@_attrs_define +class EvalPromptSetsDeleteResponse: + """ + Attributes: + cancelled_job_count (int): Number of in-flight agentic jobs associated with this prompt set that were cancelled + as part of the archive. + is_archived (bool): Always `true` on success — archives the prompt set. + """ + + cancelled_job_count: int + is_archived: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + cancelled_job_count = self.cancelled_job_count + + is_archived = self.is_archived + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "cancelled_job_count": cancelled_job_count, + "is_archived": is_archived, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + cancelled_job_count = d.pop("cancelled_job_count") + + is_archived = d.pop("is_archived") + + eval_prompt_sets_delete_response = cls( + cancelled_job_count=cancelled_job_count, + is_archived=is_archived, + ) + + eval_prompt_sets_delete_response.additional_properties = d + return eval_prompt_sets_delete_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt_sets_get_response.py b/omni_python_sdk/models/eval_prompt_sets_get_response.py new file mode 100644 index 0000000..93d30a0 --- /dev/null +++ b/omni_python_sdk/models/eval_prompt_sets_get_response.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.eval_prompt_set import EvalPromptSet + + +T = TypeVar("T", bound="EvalPromptSetsGetResponse") + + +@_attrs_define +class EvalPromptSetsGetResponse: + """ + Attributes: + prompt_set (EvalPromptSet): + """ + + prompt_set: EvalPromptSet + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + prompt_set = self.prompt_set.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "prompt_set": prompt_set, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_prompt_set import EvalPromptSet + + d = dict(src_dict) + prompt_set = EvalPromptSet.from_dict(d.pop("prompt_set")) + + eval_prompt_sets_get_response = cls( + prompt_set=prompt_set, + ) + + eval_prompt_sets_get_response.additional_properties = d + return eval_prompt_sets_get_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt_sets_list_response.py b/omni_python_sdk/models/eval_prompt_sets_list_response.py new file mode 100644 index 0000000..46e1798 --- /dev/null +++ b/omni_python_sdk/models/eval_prompt_sets_list_response.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.eval_prompt_set_list_item import EvalPromptSetListItem + + +T = TypeVar("T", bound="EvalPromptSetsListResponse") + + +@_attrs_define +class EvalPromptSetsListResponse: + """ + Attributes: + prompt_sets (list[EvalPromptSetListItem]): Prompt sets matching the query, sorted alphabetically by name. + """ + + prompt_sets: list[EvalPromptSetListItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + prompt_sets = [] + for prompt_sets_item_data in self.prompt_sets: + prompt_sets_item = prompt_sets_item_data.to_dict() + prompt_sets.append(prompt_sets_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "prompt_sets": prompt_sets, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_prompt_set_list_item import EvalPromptSetListItem + + d = dict(src_dict) + prompt_sets = [] + _prompt_sets = d.pop("prompt_sets") + for prompt_sets_item_data in _prompt_sets: + prompt_sets_item = EvalPromptSetListItem.from_dict(prompt_sets_item_data) + + prompt_sets.append(prompt_sets_item) + + eval_prompt_sets_list_response = cls( + prompt_sets=prompt_sets, + ) + + eval_prompt_sets_list_response.additional_properties = d + return eval_prompt_sets_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt_sets_unarchive_response.py b/omni_python_sdk/models/eval_prompt_sets_unarchive_response.py new file mode 100644 index 0000000..452c78a --- /dev/null +++ b/omni_python_sdk/models/eval_prompt_sets_unarchive_response.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.eval_prompt_set import EvalPromptSet + + +T = TypeVar("T", bound="EvalPromptSetsUnarchiveResponse") + + +@_attrs_define +class EvalPromptSetsUnarchiveResponse: + """ + Attributes: + prompt_set (EvalPromptSet): + """ + + prompt_set: EvalPromptSet + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + prompt_set = self.prompt_set.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "prompt_set": prompt_set, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_prompt_set import EvalPromptSet + + d = dict(src_dict) + prompt_set = EvalPromptSet.from_dict(d.pop("prompt_set")) + + eval_prompt_sets_unarchive_response = cls( + prompt_set=prompt_set, + ) + + eval_prompt_sets_unarchive_response.additional_properties = d + return eval_prompt_sets_unarchive_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt_sets_update_body.py b/omni_python_sdk/models/eval_prompt_sets_update_body.py new file mode 100644 index 0000000..4c88e8c --- /dev/null +++ b/omni_python_sdk/models/eval_prompt_sets_update_body.py @@ -0,0 +1,111 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.eval_prompt_sets_update_body_prompts_item import EvalPromptSetsUpdateBodyPromptsItem + + +T = TypeVar("T", bound="EvalPromptSetsUpdateBody") + + +@_attrs_define +class EvalPromptSetsUpdateBody: + """ + Attributes: + description (None | str | Unset): New description for the prompt set. Pass `null` to clear. Max 1024 characters. + name (str | Unset): New human-readable name for the prompt set. 255 characters or fewer. + prompts (list[EvalPromptSetsUpdateBodyPromptsItem] | Unset): Full desired set of prompts after the update. + Prompts omitted from this list are deleted; new prompts (no `id`) are appended in body order. Existing prompts + retain their original position — reordering is not supported on this endpoint. At most 25 prompts total. + """ + + description: None | str | Unset = UNSET + name: str | Unset = UNSET + prompts: list[EvalPromptSetsUpdateBodyPromptsItem] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + name = self.name + + prompts: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.prompts, Unset): + prompts = [] + for prompts_item_data in self.prompts: + prompts_item = prompts_item_data.to_dict() + prompts.append(prompts_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if description is not UNSET: + field_dict["description"] = description + if name is not UNSET: + field_dict["name"] = name + if prompts is not UNSET: + field_dict["prompts"] = prompts + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_prompt_sets_update_body_prompts_item import EvalPromptSetsUpdateBodyPromptsItem + + d = dict(src_dict) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + name = d.pop("name", UNSET) + + _prompts = d.pop("prompts", UNSET) + prompts: list[EvalPromptSetsUpdateBodyPromptsItem] | Unset = UNSET + if _prompts is not UNSET: + prompts = [] + for prompts_item_data in _prompts: + prompts_item = EvalPromptSetsUpdateBodyPromptsItem.from_dict(prompts_item_data) + + prompts.append(prompts_item) + + eval_prompt_sets_update_body = cls( + description=description, + name=name, + prompts=prompts, + ) + + eval_prompt_sets_update_body.additional_properties = d + return eval_prompt_sets_update_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt_sets_update_body_prompts_item.py b/omni_python_sdk/models/eval_prompt_sets_update_body_prompts_item.py new file mode 100644 index 0000000..93b35b4 --- /dev/null +++ b/omni_python_sdk/models/eval_prompt_sets_update_body_prompts_item.py @@ -0,0 +1,103 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="EvalPromptSetsUpdateBodyPromptsItem") + + +@_attrs_define +class EvalPromptSetsUpdateBodyPromptsItem: + """ + Attributes: + prompt_text (str): Updated or new prompt text. Max 8000 characters. Example: What are the top 10 products by + revenue this quarter?. + expectation (None | str | Unset): Optional expectation the analysis judge scores the analysis against. Pass + `null` to clear. Max 16000 characters. Example: The top product by revenue should be Aniseed Syrup.. + id (UUID | Unset): Existing prompt id. When provided, updates that prompt; when omitted, a new prompt is + created. Prompts not included in this list are removed. + """ + + prompt_text: str + expectation: None | str | Unset = UNSET + id: UUID | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + prompt_text = self.prompt_text + + expectation: None | str | Unset + if isinstance(self.expectation, Unset): + expectation = UNSET + else: + expectation = self.expectation + + id: str | Unset = UNSET + if not isinstance(self.id, Unset): + id = str(self.id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "prompt_text": prompt_text, + } + ) + if expectation is not UNSET: + field_dict["expectation"] = expectation + if id is not UNSET: + field_dict["id"] = id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + prompt_text = d.pop("prompt_text") + + def _parse_expectation(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + expectation = _parse_expectation(d.pop("expectation", UNSET)) + + _id = d.pop("id", UNSET) + id: UUID | Unset + if isinstance(_id, Unset): + id = UNSET + else: + id = UUID(_id) + + eval_prompt_sets_update_body_prompts_item = cls( + prompt_text=prompt_text, + expectation=expectation, + id=id, + ) + + eval_prompt_sets_update_body_prompts_item.additional_properties = d + return eval_prompt_sets_update_body_prompts_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_prompt_sets_update_response.py b/omni_python_sdk/models/eval_prompt_sets_update_response.py new file mode 100644 index 0000000..bacfaf2 --- /dev/null +++ b/omni_python_sdk/models/eval_prompt_sets_update_response.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.eval_prompt_set import EvalPromptSet + + +T = TypeVar("T", bound="EvalPromptSetsUpdateResponse") + + +@_attrs_define +class EvalPromptSetsUpdateResponse: + """ + Attributes: + prompt_set (EvalPromptSet): + """ + + prompt_set: EvalPromptSet + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + prompt_set = self.prompt_set.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "prompt_set": prompt_set, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_prompt_set import EvalPromptSet + + d = dict(src_dict) + prompt_set = EvalPromptSet.from_dict(d.pop("prompt_set")) + + eval_prompt_sets_update_response = cls( + prompt_set=prompt_set, + ) + + eval_prompt_sets_update_response.additional_properties = d + return eval_prompt_sets_update_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_run_detail.py b/omni_python_sdk/models/eval_run_detail.py new file mode 100644 index 0000000..539ff10 --- /dev/null +++ b/omni_python_sdk/models/eval_run_detail.py @@ -0,0 +1,212 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.eval_run_detail_status import EvalRunDetailStatus, check_eval_run_detail_status + +if TYPE_CHECKING: + from ..models.eval_run_result import EvalRunResult + + +T = TypeVar("T", bound="EvalRunDetail") + + +@_attrs_define +class EvalRunDetail: + """The newly created run with its initial results. + + Attributes: + branch_id (None | UUID): Optional branch ID the run was executed against. Null when run against the main shared + model. + branch_name (None | str): Display name for the branch, if `branch_id` is set. + completed_at (None | str): ISO 8601 timestamp when the run reached a terminal state. + created_at (None | str): ISO 8601 timestamp when the run was created. Example: 2025-01-15T10:00:00.000Z. + description (None | str): Optional human-readable description for the run. + id (UUID): Unique identifier for the run. Example: 660e8400-e29b-41d4-a716-446655440001. + is_archived (bool): Whether the run has been archived. + model_id (UUID): The shared model this run was executed against. Example: 880e8400-e29b-41d4-a716-446655440003. + prompt_set_id (UUID): The prompt set this run was created from. Example: 550e8400-e29b-41d4-a716-446655440000. + results (list[EvalRunResult]): Per-prompt results for this run, ordered by their creation order in the prompt + set. + run_number (int): Sequential, per-prompt-set run number. Example: 3. + status (EvalRunDetailStatus): Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly + once. Example: RUNNING. + """ + + branch_id: None | UUID + branch_name: None | str + completed_at: None | str + created_at: None | str + description: None | str + id: UUID + is_archived: bool + model_id: UUID + prompt_set_id: UUID + results: list[EvalRunResult] + run_number: int + status: EvalRunDetailStatus + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + branch_id: None | str + if isinstance(self.branch_id, UUID): + branch_id = str(self.branch_id) + else: + branch_id = self.branch_id + + branch_name: None | str + branch_name = self.branch_name + + completed_at: None | str + completed_at = self.completed_at + + created_at: None | str + created_at = self.created_at + + description: None | str + description = self.description + + id = str(self.id) + + is_archived = self.is_archived + + model_id = str(self.model_id) + + prompt_set_id = str(self.prompt_set_id) + + results = [] + for results_item_data in self.results: + results_item = results_item_data.to_dict() + results.append(results_item) + + run_number = self.run_number + + status: str = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "branch_id": branch_id, + "branch_name": branch_name, + "completed_at": completed_at, + "created_at": created_at, + "description": description, + "id": id, + "is_archived": is_archived, + "model_id": model_id, + "prompt_set_id": prompt_set_id, + "results": results, + "run_number": run_number, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_run_result import EvalRunResult + + d = dict(src_dict) + + def _parse_branch_id(data: object) -> None | UUID: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + branch_id_type_0 = UUID(data) + + return branch_id_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UUID, data) + + branch_id = _parse_branch_id(d.pop("branch_id")) + + def _parse_branch_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + branch_name = _parse_branch_name(d.pop("branch_name")) + + def _parse_completed_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + completed_at = _parse_completed_at(d.pop("completed_at")) + + def _parse_created_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + created_at = _parse_created_at(d.pop("created_at")) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + id = UUID(d.pop("id")) + + is_archived = d.pop("is_archived") + + model_id = UUID(d.pop("model_id")) + + prompt_set_id = UUID(d.pop("prompt_set_id")) + + results = [] + _results = d.pop("results") + for results_item_data in _results: + results_item = EvalRunResult.from_dict(results_item_data) + + results.append(results_item) + + run_number = d.pop("run_number") + + status = check_eval_run_detail_status(d.pop("status")) + + eval_run_detail = cls( + branch_id=branch_id, + branch_name=branch_name, + completed_at=completed_at, + created_at=created_at, + description=description, + id=id, + is_archived=is_archived, + model_id=model_id, + prompt_set_id=prompt_set_id, + results=results, + run_number=run_number, + status=status, + ) + + eval_run_detail.additional_properties = d + return eval_run_detail + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_run_detail_status.py b/omni_python_sdk/models/eval_run_detail_status.py new file mode 100644 index 0000000..58b022f --- /dev/null +++ b/omni_python_sdk/models/eval_run_detail_status.py @@ -0,0 +1,15 @@ +from typing import Literal + +EvalRunDetailStatus = Literal["CANCELLED", "COMPLETE", "RUNNING"] + +EVAL_RUN_DETAIL_STATUS_VALUES: set[EvalRunDetailStatus] = { + "CANCELLED", + "COMPLETE", + "RUNNING", +} + + +def check_eval_run_detail_status(value: str) -> EvalRunDetailStatus: + if value in EVAL_RUN_DETAIL_STATUS_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {EVAL_RUN_DETAIL_STATUS_VALUES!r}") diff --git a/omni_python_sdk/models/eval_run_list_item.py b/omni_python_sdk/models/eval_run_list_item.py new file mode 100644 index 0000000..5f72990 --- /dev/null +++ b/omni_python_sdk/models/eval_run_list_item.py @@ -0,0 +1,202 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.eval_run_list_item_status import EvalRunListItemStatus, check_eval_run_list_item_status + +if TYPE_CHECKING: + from ..models.eval_run_stats import EvalRunStats + + +T = TypeVar("T", bound="EvalRunListItem") + + +@_attrs_define +class EvalRunListItem: + """ + Attributes: + branch_id (None | UUID): Optional branch ID the run was executed against. Null when run against the main shared + model. + branch_name (None | str): Display name for the branch, if `branch_id` is set. + completed_at (None | str): ISO 8601 timestamp when the run reached a terminal state. + created_at (None | str): ISO 8601 timestamp when the run was created. Example: 2025-01-15T10:00:00.000Z. + description (None | str): Optional human-readable description for the run. + id (UUID): Unique identifier for the run. Example: 660e8400-e29b-41d4-a716-446655440001. + is_archived (bool): Whether the run has been archived. + model_id (UUID): The shared model this run was executed against. Example: 880e8400-e29b-41d4-a716-446655440003. + prompt_set_id (UUID): The prompt set this run was created from. Example: 550e8400-e29b-41d4-a716-446655440000. + run_number (int): Sequential, per-prompt-set run number. Example: 3. + stats (EvalRunStats): + status (EvalRunListItemStatus): Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly + once. Example: RUNNING. + """ + + branch_id: None | UUID + branch_name: None | str + completed_at: None | str + created_at: None | str + description: None | str + id: UUID + is_archived: bool + model_id: UUID + prompt_set_id: UUID + run_number: int + stats: EvalRunStats + status: EvalRunListItemStatus + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + branch_id: None | str + if isinstance(self.branch_id, UUID): + branch_id = str(self.branch_id) + else: + branch_id = self.branch_id + + branch_name: None | str + branch_name = self.branch_name + + completed_at: None | str + completed_at = self.completed_at + + created_at: None | str + created_at = self.created_at + + description: None | str + description = self.description + + id = str(self.id) + + is_archived = self.is_archived + + model_id = str(self.model_id) + + prompt_set_id = str(self.prompt_set_id) + + run_number = self.run_number + + stats = self.stats.to_dict() + + status: str = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "branch_id": branch_id, + "branch_name": branch_name, + "completed_at": completed_at, + "created_at": created_at, + "description": description, + "id": id, + "is_archived": is_archived, + "model_id": model_id, + "prompt_set_id": prompt_set_id, + "run_number": run_number, + "stats": stats, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_run_stats import EvalRunStats + + d = dict(src_dict) + + def _parse_branch_id(data: object) -> None | UUID: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + branch_id_type_0 = UUID(data) + + return branch_id_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UUID, data) + + branch_id = _parse_branch_id(d.pop("branch_id")) + + def _parse_branch_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + branch_name = _parse_branch_name(d.pop("branch_name")) + + def _parse_completed_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + completed_at = _parse_completed_at(d.pop("completed_at")) + + def _parse_created_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + created_at = _parse_created_at(d.pop("created_at")) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + id = UUID(d.pop("id")) + + is_archived = d.pop("is_archived") + + model_id = UUID(d.pop("model_id")) + + prompt_set_id = UUID(d.pop("prompt_set_id")) + + run_number = d.pop("run_number") + + stats = EvalRunStats.from_dict(d.pop("stats")) + + status = check_eval_run_list_item_status(d.pop("status")) + + eval_run_list_item = cls( + branch_id=branch_id, + branch_name=branch_name, + completed_at=completed_at, + created_at=created_at, + description=description, + id=id, + is_archived=is_archived, + model_id=model_id, + prompt_set_id=prompt_set_id, + run_number=run_number, + stats=stats, + status=status, + ) + + eval_run_list_item.additional_properties = d + return eval_run_list_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_run_list_item_status.py b/omni_python_sdk/models/eval_run_list_item_status.py new file mode 100644 index 0000000..d149298 --- /dev/null +++ b/omni_python_sdk/models/eval_run_list_item_status.py @@ -0,0 +1,15 @@ +from typing import Literal + +EvalRunListItemStatus = Literal["CANCELLED", "COMPLETE", "RUNNING"] + +EVAL_RUN_LIST_ITEM_STATUS_VALUES: set[EvalRunListItemStatus] = { + "CANCELLED", + "COMPLETE", + "RUNNING", +} + + +def check_eval_run_list_item_status(value: str) -> EvalRunListItemStatus: + if value in EVAL_RUN_LIST_ITEM_STATUS_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {EVAL_RUN_LIST_ITEM_STATUS_VALUES!r}") diff --git a/omni_python_sdk/models/eval_run_result.py b/omni_python_sdk/models/eval_run_result.py new file mode 100644 index 0000000..6c319d9 --- /dev/null +++ b/omni_python_sdk/models/eval_run_result.py @@ -0,0 +1,236 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.eval_run_result_agentic_job import EvalRunResultAgenticJob + + +T = TypeVar("T", bound="EvalRunResult") + + +@_attrs_define +class EvalRunResult: + """ + Attributes: + agentic_job (EvalRunResultAgenticJob): + ai_timing_ms (int | None): Strict main-agent LLM processing time in milliseconds — the measured model-call + duration, excluding tool execution and subagent model calls (those count toward `tool_timing_ms`). Shown as "AI + time" in the UI. Runs recorded before this was measured fall back to an approximation (`timing_ms` minus tool + latency). Example: 4121. + cost (float | None): Total LLM cost (USD) for this prompt, if available. Example: 0.0021. + error_reason (None | str): Failure reason string for prompts whose underlying job failed. + expectation (None | str): The prompt's expectation as of run creation (snapshotted, so later prompt edits don't + change past runs), or null when none was set. The analysis judge scores the analysis against it. Example: The + top product by revenue should be Aniseed Syrup.. + id (UUID): Unique identifier for the run result row. Example: aa0e8400-e29b-41d4-a716-446655440005. + prompt (str): The prompt text that was evaluated. Example: What are the top 5 products by revenue?. + query_count (int | None): Number of warehouse queries the underlying job ran. Null for runs executed before this + metric was recorded. Example: 4. + query_timing_ms (int | None): Total wall-clock time (milliseconds) the underlying job spent running warehouse + queries — a proxy for query execution time. Null for runs executed before this metric was recorded. Example: + 1800. + score (float | None): Numeric judge score for this prompt result, if scoring ran. Example: 0.9. + scoring_cost (float | None): Total LLM cost (USD) for scoring this prompt result. Example: 0.0004. + timing_ms (int | None): Total `/generate` wall-time in milliseconds — LLM processing plus inner-loop tool + execution. `ai_timing_ms` and `tool_timing_ms` split this; warehouse query time is separate (`query_timing_ms`). + Example: 4321. + tool_timing_ms (int | None): Inner-loop tool latency in milliseconds — time spent running tools the model + invoked (model and field-value lookups, query planning), excluding the warehouse query itself + (`query_timing_ms`). Null for runs recorded before per-tool latency was tracked. Example: 200. + """ + + agentic_job: EvalRunResultAgenticJob + ai_timing_ms: int | None + cost: float | None + error_reason: None | str + expectation: None | str + id: UUID + prompt: str + query_count: int | None + query_timing_ms: int | None + score: float | None + scoring_cost: float | None + timing_ms: int | None + tool_timing_ms: int | None + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + agentic_job = self.agentic_job.to_dict() + + ai_timing_ms: int | None + ai_timing_ms = self.ai_timing_ms + + cost: float | None + cost = self.cost + + error_reason: None | str + error_reason = self.error_reason + + expectation: None | str + expectation = self.expectation + + id = str(self.id) + + prompt = self.prompt + + query_count: int | None + query_count = self.query_count + + query_timing_ms: int | None + query_timing_ms = self.query_timing_ms + + score: float | None + score = self.score + + scoring_cost: float | None + scoring_cost = self.scoring_cost + + timing_ms: int | None + timing_ms = self.timing_ms + + tool_timing_ms: int | None + tool_timing_ms = self.tool_timing_ms + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "agentic_job": agentic_job, + "ai_timing_ms": ai_timing_ms, + "cost": cost, + "error_reason": error_reason, + "expectation": expectation, + "id": id, + "prompt": prompt, + "query_count": query_count, + "query_timing_ms": query_timing_ms, + "score": score, + "scoring_cost": scoring_cost, + "timing_ms": timing_ms, + "tool_timing_ms": tool_timing_ms, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_run_result_agentic_job import EvalRunResultAgenticJob + + d = dict(src_dict) + agentic_job = EvalRunResultAgenticJob.from_dict(d.pop("agentic_job")) + + def _parse_ai_timing_ms(data: object) -> int | None: + if data is None: + return data + return cast(int | None, data) + + ai_timing_ms = _parse_ai_timing_ms(d.pop("ai_timing_ms")) + + def _parse_cost(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + cost = _parse_cost(d.pop("cost")) + + def _parse_error_reason(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + error_reason = _parse_error_reason(d.pop("error_reason")) + + def _parse_expectation(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + expectation = _parse_expectation(d.pop("expectation")) + + id = UUID(d.pop("id")) + + prompt = d.pop("prompt") + + def _parse_query_count(data: object) -> int | None: + if data is None: + return data + return cast(int | None, data) + + query_count = _parse_query_count(d.pop("query_count")) + + def _parse_query_timing_ms(data: object) -> int | None: + if data is None: + return data + return cast(int | None, data) + + query_timing_ms = _parse_query_timing_ms(d.pop("query_timing_ms")) + + def _parse_score(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + score = _parse_score(d.pop("score")) + + def _parse_scoring_cost(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + scoring_cost = _parse_scoring_cost(d.pop("scoring_cost")) + + def _parse_timing_ms(data: object) -> int | None: + if data is None: + return data + return cast(int | None, data) + + timing_ms = _parse_timing_ms(d.pop("timing_ms")) + + def _parse_tool_timing_ms(data: object) -> int | None: + if data is None: + return data + return cast(int | None, data) + + tool_timing_ms = _parse_tool_timing_ms(d.pop("tool_timing_ms")) + + eval_run_result = cls( + agentic_job=agentic_job, + ai_timing_ms=ai_timing_ms, + cost=cost, + error_reason=error_reason, + expectation=expectation, + id=id, + prompt=prompt, + query_count=query_count, + query_timing_ms=query_timing_ms, + score=score, + scoring_cost=scoring_cost, + timing_ms=timing_ms, + tool_timing_ms=tool_timing_ms, + ) + + eval_run_result.additional_properties = d + return eval_run_result + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_run_result_agentic_job.py b/omni_python_sdk/models/eval_run_result_agentic_job.py new file mode 100644 index 0000000..38fb27c --- /dev/null +++ b/omni_python_sdk/models/eval_run_result_agentic_job.py @@ -0,0 +1,102 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.eval_run_result_agentic_job_state import ( + EvalRunResultAgenticJobState, + check_eval_run_result_agentic_job_state, +) + +T = TypeVar("T", bound="EvalRunResultAgenticJob") + + +@_attrs_define +class EvalRunResultAgenticJob: + """ + Attributes: + conversation_id (None | UUID): Conversation the agentic job belongs to. Example: + 770e8400-e29b-41d4-a716-446655440002. + id (UUID): Agentic job identifier. Example: 990e8400-e29b-41d4-a716-446655440004. + state (EvalRunResultAgenticJobState): Current state of the agentic job that ran this prompt. Example: COMPLETE. + """ + + conversation_id: None | UUID + id: UUID + state: EvalRunResultAgenticJobState + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + conversation_id: None | str + if isinstance(self.conversation_id, UUID): + conversation_id = str(self.conversation_id) + else: + conversation_id = self.conversation_id + + id = str(self.id) + + state: str = self.state + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "conversation_id": conversation_id, + "id": id, + "state": state, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_conversation_id(data: object) -> None | UUID: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + conversation_id_type_0 = UUID(data) + + return conversation_id_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UUID, data) + + conversation_id = _parse_conversation_id(d.pop("conversation_id")) + + id = UUID(d.pop("id")) + + state = check_eval_run_result_agentic_job_state(d.pop("state")) + + eval_run_result_agentic_job = cls( + conversation_id=conversation_id, + id=id, + state=state, + ) + + eval_run_result_agentic_job.additional_properties = d + return eval_run_result_agentic_job + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_run_result_agentic_job_state.py b/omni_python_sdk/models/eval_run_result_agentic_job_state.py new file mode 100644 index 0000000..51b18c5 --- /dev/null +++ b/omni_python_sdk/models/eval_run_result_agentic_job_state.py @@ -0,0 +1,18 @@ +from typing import Literal + +EvalRunResultAgenticJobState = Literal["CANCELLED", "COMPLETE", "DELIVERING", "EXECUTING", "FAILED", "QUEUED"] + +EVAL_RUN_RESULT_AGENTIC_JOB_STATE_VALUES: set[EvalRunResultAgenticJobState] = { + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED", +} + + +def check_eval_run_result_agentic_job_state(value: str) -> EvalRunResultAgenticJobState: + if value in EVAL_RUN_RESULT_AGENTIC_JOB_STATE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {EVAL_RUN_RESULT_AGENTIC_JOB_STATE_VALUES!r}") diff --git a/omni_python_sdk/models/eval_run_stats.py b/omni_python_sdk/models/eval_run_stats.py new file mode 100644 index 0000000..0904ba7 --- /dev/null +++ b/omni_python_sdk/models/eval_run_stats.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalRunStats") + + +@_attrs_define +class EvalRunStats: + """ + Attributes: + terminal (int): Number of per-prompt jobs that have reached a terminal state (COMPLETE, FAILED, or CANCELLED). + Example: 8. + total (int): Total number of per-prompt jobs in the run. Example: 12. + """ + + terminal: int + total: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + terminal = self.terminal + + total = self.total + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "terminal": terminal, + "total": total, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + terminal = d.pop("terminal") + + total = d.pop("total") + + eval_run_stats = cls( + terminal=terminal, + total=total, + ) + + eval_run_stats.additional_properties = d + return eval_run_stats + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_runs_cancel_response.py b/omni_python_sdk/models/eval_runs_cancel_response.py new file mode 100644 index 0000000..9ba2680 --- /dev/null +++ b/omni_python_sdk/models/eval_runs_cancel_response.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.eval_run_detail import EvalRunDetail + + +T = TypeVar("T", bound="EvalRunsCancelResponse") + + +@_attrs_define +class EvalRunsCancelResponse: + """ + Attributes: + cancelled (int): Number of per-prompt agentic jobs that were cancelled by this request. Example: 4. + run (EvalRunDetail): The newly created run with its initial results. + total (int): Total number of per-prompt jobs in the run. Example: 12. + """ + + cancelled: int + run: EvalRunDetail + total: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + cancelled = self.cancelled + + run = self.run.to_dict() + + total = self.total + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "cancelled": cancelled, + "run": run, + "total": total, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_run_detail import EvalRunDetail + + d = dict(src_dict) + cancelled = d.pop("cancelled") + + run = EvalRunDetail.from_dict(d.pop("run")) + + total = d.pop("total") + + eval_runs_cancel_response = cls( + cancelled=cancelled, + run=run, + total=total, + ) + + eval_runs_cancel_response.additional_properties = d + return eval_runs_cancel_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_runs_create_body.py b/omni_python_sdk/models/eval_runs_create_body.py new file mode 100644 index 0000000..0d66e98 --- /dev/null +++ b/omni_python_sdk/models/eval_runs_create_body.py @@ -0,0 +1,107 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.eval_runs_create_body_run_config import EvalRunsCreateBodyRunConfig + + +T = TypeVar("T", bound="EvalRunsCreateBody") + + +@_attrs_define +class EvalRunsCreateBody: + """ + Attributes: + prompt_set_id (UUID): The prompt set to execute. Example: 550e8400-e29b-41d4-a716-446655440000. + description (None | str | Unset): Optional human-readable description for the run. Pass `null` to clear (or + omit). Max 1024 characters. Example: Re-running after switching to gpt-4o for query generation. + run_config (EvalRunsCreateBodyRunConfig | Unset): Per-run configuration. Optional — omit if no overrides. + """ + + prompt_set_id: UUID + description: None | str | Unset = UNSET + run_config: EvalRunsCreateBodyRunConfig | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + prompt_set_id = str(self.prompt_set_id) + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + run_config: dict[str, Any] | Unset = UNSET + if not isinstance(self.run_config, Unset): + run_config = self.run_config.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "prompt_set_id": prompt_set_id, + } + ) + if description is not UNSET: + field_dict["description"] = description + if run_config is not UNSET: + field_dict["run_config"] = run_config + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_runs_create_body_run_config import EvalRunsCreateBodyRunConfig + + d = dict(src_dict) + prompt_set_id = UUID(d.pop("prompt_set_id")) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + _run_config = d.pop("run_config", UNSET) + run_config: EvalRunsCreateBodyRunConfig | Unset + if isinstance(_run_config, Unset): + run_config = UNSET + else: + run_config = EvalRunsCreateBodyRunConfig.from_dict(_run_config) + + eval_runs_create_body = cls( + prompt_set_id=prompt_set_id, + description=description, + run_config=run_config, + ) + + eval_runs_create_body.additional_properties = d + return eval_runs_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_runs_create_body_run_config.py b/omni_python_sdk/models/eval_runs_create_body_run_config.py new file mode 100644 index 0000000..77bec0c --- /dev/null +++ b/omni_python_sdk/models/eval_runs_create_body_run_config.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="EvalRunsCreateBodyRunConfig") + + +@_attrs_define +class EvalRunsCreateBodyRunConfig: + """Per-run configuration. Optional — omit if no overrides. + + Attributes: + branch_id (UUID | Unset): Optional branch ID to run against. Must be a branch of the prompt set's model. + Example: 440e8400-e29b-41d4-a716-446655440006. + """ + + branch_id: UUID | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if branch_id is not UNSET: + field_dict["branch_id"] = branch_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + _branch_id = d.pop("branch_id", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + eval_runs_create_body_run_config = cls( + branch_id=branch_id, + ) + + eval_runs_create_body_run_config.additional_properties = d + return eval_runs_create_body_run_config + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_runs_create_response.py b/omni_python_sdk/models/eval_runs_create_response.py new file mode 100644 index 0000000..3fd49ee --- /dev/null +++ b/omni_python_sdk/models/eval_runs_create_response.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.eval_run_detail import EvalRunDetail + + +T = TypeVar("T", bound="EvalRunsCreateResponse") + + +@_attrs_define +class EvalRunsCreateResponse: + """ + Attributes: + job_count (int): Number of per-prompt agentic jobs created for this run (one per prompt that fanned out + successfully). Enqueue onto the work queue happens after creation and is best-effort, so this count reflects + jobs created, not necessarily those successfully enqueued. Example: 12. + run (EvalRunDetail): The newly created run with its initial results. + """ + + job_count: int + run: EvalRunDetail + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + job_count = self.job_count + + run = self.run.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "job_count": job_count, + "run": run, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_run_detail import EvalRunDetail + + d = dict(src_dict) + job_count = d.pop("job_count") + + run = EvalRunDetail.from_dict(d.pop("run")) + + eval_runs_create_response = cls( + job_count=job_count, + run=run, + ) + + eval_runs_create_response.additional_properties = d + return eval_runs_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_runs_delete_response.py b/omni_python_sdk/models/eval_runs_delete_response.py new file mode 100644 index 0000000..3ddc22d --- /dev/null +++ b/omni_python_sdk/models/eval_runs_delete_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalRunsDeleteResponse") + + +@_attrs_define +class EvalRunsDeleteResponse: + """ + Attributes: + is_archived (bool): Always `true` on success — the run has been archived. + """ + + is_archived: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + is_archived = self.is_archived + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "is_archived": is_archived, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + is_archived = d.pop("is_archived") + + eval_runs_delete_response = cls( + is_archived=is_archived, + ) + + eval_runs_delete_response.additional_properties = d + return eval_runs_delete_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_runs_get_response.py b/omni_python_sdk/models/eval_runs_get_response.py new file mode 100644 index 0000000..100344c --- /dev/null +++ b/omni_python_sdk/models/eval_runs_get_response.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.eval_run_detail import EvalRunDetail + + +T = TypeVar("T", bound="EvalRunsGetResponse") + + +@_attrs_define +class EvalRunsGetResponse: + """ + Attributes: + run (EvalRunDetail): The newly created run with its initial results. + """ + + run: EvalRunDetail + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + run = self.run.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "run": run, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_run_detail import EvalRunDetail + + d = dict(src_dict) + run = EvalRunDetail.from_dict(d.pop("run")) + + eval_runs_get_response = cls( + run=run, + ) + + eval_runs_get_response.additional_properties = d + return eval_runs_get_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_runs_list_response.py b/omni_python_sdk/models/eval_runs_list_response.py new file mode 100644 index 0000000..94b0237 --- /dev/null +++ b/omni_python_sdk/models/eval_runs_list_response.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.eval_run_list_item import EvalRunListItem + + +T = TypeVar("T", bound="EvalRunsListResponse") + + +@_attrs_define +class EvalRunsListResponse: + """ + Attributes: + runs (list[EvalRunListItem]): Runs for the prompt set, newest first, filtered to those whose model the caller + can access. + """ + + runs: list[EvalRunListItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + runs = [] + for runs_item_data in self.runs: + runs_item = runs_item_data.to_dict() + runs.append(runs_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "runs": runs, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.eval_run_list_item import EvalRunListItem + + d = dict(src_dict) + runs = [] + _runs = d.pop("runs") + for runs_item_data in _runs: + runs_item = EvalRunListItem.from_dict(runs_item_data) + + runs.append(runs_item) + + eval_runs_list_response = cls( + runs=runs, + ) + + eval_runs_list_response.additional_properties = d + return eval_runs_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/eval_runs_unarchive_response.py b/omni_python_sdk/models/eval_runs_unarchive_response.py new file mode 100644 index 0000000..c065943 --- /dev/null +++ b/omni_python_sdk/models/eval_runs_unarchive_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="EvalRunsUnarchiveResponse") + + +@_attrs_define +class EvalRunsUnarchiveResponse: + """ + Attributes: + is_archived (bool): Always `false` on success — the run has been unarchived. + """ + + is_archived: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + is_archived = self.is_archived + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "is_archived": is_archived, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + is_archived = d.pop("is_archived") + + eval_runs_unarchive_response = cls( + is_archived=is_archived, + ) + + eval_runs_unarchive_response.additional_properties = d + return eval_runs_unarchive_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_add_permissions_body.py b/omni_python_sdk/models/folders_add_permissions_body.py new file mode 100644 index 0000000..f6eff77 --- /dev/null +++ b/omni_python_sdk/models/folders_add_permissions_body.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define + +from ..models.folders_add_permissions_body_role import ( + FoldersAddPermissionsBodyRole, + check_folders_add_permissions_body_role, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="FoldersAddPermissionsBody") + + +@_attrs_define +class FoldersAddPermissionsBody: + """ + Attributes: + role (FoldersAddPermissionsBodyRole): Content role to assign (VIEWER, EDITOR, or MANAGER) Example: VIEWER. + access_boost (bool | Unset): Whether to grant access boost Default: False. + user_group_ids (list[str] | Unset): User group IDs to grant permission to + user_ids (list[UUID] | Unset): User IDs to grant permission to + """ + + role: FoldersAddPermissionsBodyRole + access_boost: bool | Unset = False + user_group_ids: list[str] | Unset = UNSET + user_ids: list[UUID] | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + role: str = self.role + + access_boost = self.access_boost + + user_group_ids: list[str] | Unset = UNSET + if not isinstance(self.user_group_ids, Unset): + user_group_ids = self.user_group_ids + + user_ids: list[str] | Unset = UNSET + if not isinstance(self.user_ids, Unset): + user_ids = [] + for user_ids_item_data in self.user_ids: + user_ids_item = str(user_ids_item_data) + user_ids.append(user_ids_item) + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "role": role, + } + ) + if access_boost is not UNSET: + field_dict["accessBoost"] = access_boost + if user_group_ids is not UNSET: + field_dict["userGroupIds"] = user_group_ids + if user_ids is not UNSET: + field_dict["userIds"] = user_ids + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + role = check_folders_add_permissions_body_role(d.pop("role")) + + access_boost = d.pop("accessBoost", UNSET) + + user_group_ids = cast(list[str], d.pop("userGroupIds", UNSET)) + + _user_ids = d.pop("userIds", UNSET) + user_ids: list[UUID] | Unset = UNSET + if _user_ids is not UNSET: + user_ids = [] + for user_ids_item_data in _user_ids: + user_ids_item = UUID(user_ids_item_data) + + user_ids.append(user_ids_item) + + folders_add_permissions_body = cls( + role=role, + access_boost=access_boost, + user_group_ids=user_group_ids, + user_ids=user_ids, + ) + + return folders_add_permissions_body diff --git a/omni_python_sdk/models/folders_add_permissions_body_role.py b/omni_python_sdk/models/folders_add_permissions_body_role.py new file mode 100644 index 0000000..108f50b --- /dev/null +++ b/omni_python_sdk/models/folders_add_permissions_body_role.py @@ -0,0 +1,17 @@ +from typing import Literal + +FoldersAddPermissionsBodyRole = Literal["EDITOR", "EXPLORER", "MANAGER", "NO_ACCESS", "VIEWER"] + +FOLDERS_ADD_PERMISSIONS_BODY_ROLE_VALUES: set[FoldersAddPermissionsBodyRole] = { + "EDITOR", + "EXPLORER", + "MANAGER", + "NO_ACCESS", + "VIEWER", +} + + +def check_folders_add_permissions_body_role(value: str) -> FoldersAddPermissionsBodyRole: + if value in FOLDERS_ADD_PERMISSIONS_BODY_ROLE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {FOLDERS_ADD_PERMISSIONS_BODY_ROLE_VALUES!r}") diff --git a/omni_python_sdk/models/folders_add_permissions_response.py b/omni_python_sdk/models/folders_add_permissions_response.py new file mode 100644 index 0000000..b580282 --- /dev/null +++ b/omni_python_sdk/models/folders_add_permissions_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="FoldersAddPermissionsResponse") + + +@_attrs_define +class FoldersAddPermissionsResponse: + """ + Attributes: + success (bool): Whether the permissions were added successfully + """ + + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + success = d.pop("success") + + folders_add_permissions_response = cls( + success=success, + ) + + folders_add_permissions_response.additional_properties = d + return folders_add_permissions_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_create_body.py b/omni_python_sdk/models/folders_create_body.py new file mode 100644 index 0000000..86fd261 --- /dev/null +++ b/omni_python_sdk/models/folders_create_body.py @@ -0,0 +1,113 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.folders_create_body_scope import FoldersCreateBodyScope, check_folders_create_body_scope +from ..types import UNSET, Unset + +T = TypeVar("T", bound="FoldersCreateBody") + + +@_attrs_define +class FoldersCreateBody: + """ + Attributes: + name (str): Name of the folder to create Example: My New Folder. + parent_folder_id (UUID | Unset): Parent folder ID (omit to create at root level) + scope (FoldersCreateBodyScope | Unset): Share scope for the folder + user_id (UUID | Unset): User ID to create the folder as (for org-scoped API keys only) + """ + + name: str + parent_folder_id: UUID | Unset = UNSET + scope: FoldersCreateBodyScope | Unset = UNSET + user_id: UUID | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + parent_folder_id: str | Unset = UNSET + if not isinstance(self.parent_folder_id, Unset): + parent_folder_id = str(self.parent_folder_id) + + scope: str | Unset = UNSET + if not isinstance(self.scope, Unset): + scope = self.scope + + user_id: str | Unset = UNSET + if not isinstance(self.user_id, Unset): + user_id = str(self.user_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + if parent_folder_id is not UNSET: + field_dict["parentFolderId"] = parent_folder_id + if scope is not UNSET: + field_dict["scope"] = scope + if user_id is not UNSET: + field_dict["userId"] = user_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + name = d.pop("name") + + _parent_folder_id = d.pop("parentFolderId", UNSET) + parent_folder_id: UUID | Unset + if isinstance(_parent_folder_id, Unset): + parent_folder_id = UNSET + else: + parent_folder_id = UUID(_parent_folder_id) + + _scope = d.pop("scope", UNSET) + scope: FoldersCreateBodyScope | Unset + if isinstance(_scope, Unset): + scope = UNSET + else: + scope = check_folders_create_body_scope(_scope) + + _user_id = d.pop("userId", UNSET) + user_id: UUID | Unset + if isinstance(_user_id, Unset): + user_id = UNSET + else: + user_id = UUID(_user_id) + + folders_create_body = cls( + name=name, + parent_folder_id=parent_folder_id, + scope=scope, + user_id=user_id, + ) + + folders_create_body.additional_properties = d + return folders_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_create_body_scope.py b/omni_python_sdk/models/folders_create_body_scope.py new file mode 100644 index 0000000..f52c225 --- /dev/null +++ b/omni_python_sdk/models/folders_create_body_scope.py @@ -0,0 +1,14 @@ +from typing import Literal + +FoldersCreateBodyScope = Literal["organization", "restricted"] + +FOLDERS_CREATE_BODY_SCOPE_VALUES: set[FoldersCreateBodyScope] = { + "organization", + "restricted", +} + + +def check_folders_create_body_scope(value: str) -> FoldersCreateBodyScope: + if value in FOLDERS_CREATE_BODY_SCOPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {FOLDERS_CREATE_BODY_SCOPE_VALUES!r}") diff --git a/omni_python_sdk/models/folders_create_response.py b/omni_python_sdk/models/folders_create_response.py new file mode 100644 index 0000000..633b429 --- /dev/null +++ b/omni_python_sdk/models/folders_create_response.py @@ -0,0 +1,96 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.folders_create_response_scope import FoldersCreateResponseScope, check_folders_create_response_scope + +T = TypeVar("T", bound="FoldersCreateResponse") + + +@_attrs_define +class FoldersCreateResponse: + """ + Attributes: + id (UUID): ID of the created folder + name (str): Name of the created folder + owner_id (UUID): User ID of the folder owner + path (str): Full path to the folder + scope (FoldersCreateResponseScope): Share scope of the folder + """ + + id: UUID + name: str + owner_id: UUID + path: str + scope: FoldersCreateResponseScope + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + name = self.name + + owner_id = str(self.owner_id) + + path = self.path + + scope: str = self.scope + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + "ownerId": owner_id, + "path": path, + "scope": scope, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = UUID(d.pop("id")) + + name = d.pop("name") + + owner_id = UUID(d.pop("ownerId")) + + path = d.pop("path") + + scope = check_folders_create_response_scope(d.pop("scope")) + + folders_create_response = cls( + id=id, + name=name, + owner_id=owner_id, + path=path, + scope=scope, + ) + + folders_create_response.additional_properties = d + return folders_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_create_response_scope.py b/omni_python_sdk/models/folders_create_response_scope.py new file mode 100644 index 0000000..a128aac --- /dev/null +++ b/omni_python_sdk/models/folders_create_response_scope.py @@ -0,0 +1,14 @@ +from typing import Literal + +FoldersCreateResponseScope = Literal["organization", "restricted"] + +FOLDERS_CREATE_RESPONSE_SCOPE_VALUES: set[FoldersCreateResponseScope] = { + "organization", + "restricted", +} + + +def check_folders_create_response_scope(value: str) -> FoldersCreateResponseScope: + if value in FOLDERS_CREATE_RESPONSE_SCOPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {FOLDERS_CREATE_RESPONSE_SCOPE_VALUES!r}") diff --git a/omni_python_sdk/models/folders_delete_response.py b/omni_python_sdk/models/folders_delete_response.py new file mode 100644 index 0000000..5dbeae9 --- /dev/null +++ b/omni_python_sdk/models/folders_delete_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="FoldersDeleteResponse") + + +@_attrs_define +class FoldersDeleteResponse: + """ + Attributes: + success (bool): Whether the folder was deleted successfully + """ + + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + success = d.pop("success") + + folders_delete_response = cls( + success=success, + ) + + folders_delete_response.additional_properties = d + return folders_delete_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_get_permissions_response.py b/omni_python_sdk/models/folders_get_permissions_response.py new file mode 100644 index 0000000..2cf4e9f --- /dev/null +++ b/omni_python_sdk/models/folders_get_permissions_response.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.folders_get_permissions_response_permits_item import FoldersGetPermissionsResponsePermitsItem + + +T = TypeVar("T", bound="FoldersGetPermissionsResponse") + + +@_attrs_define +class FoldersGetPermissionsResponse: + """ + Attributes: + permits (list[FoldersGetPermissionsResponsePermitsItem]): List of permission permits for the folder + """ + + permits: list[FoldersGetPermissionsResponsePermitsItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + permits = [] + for permits_item_data in self.permits: + permits_item = permits_item_data.to_dict() + permits.append(permits_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "permits": permits, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.folders_get_permissions_response_permits_item import FoldersGetPermissionsResponsePermitsItem + + d = dict(src_dict) + permits = [] + _permits = d.pop("permits") + for permits_item_data in _permits: + permits_item = FoldersGetPermissionsResponsePermitsItem.from_dict(permits_item_data) + + permits.append(permits_item) + + folders_get_permissions_response = cls( + permits=permits, + ) + + folders_get_permissions_response.additional_properties = d + return folders_get_permissions_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_get_permissions_response_permits_item.py b/omni_python_sdk/models/folders_get_permissions_response_permits_item.py new file mode 100644 index 0000000..e8ced8d --- /dev/null +++ b/omni_python_sdk/models/folders_get_permissions_response_permits_item.py @@ -0,0 +1,98 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="FoldersGetPermissionsResponsePermitsItem") + + +@_attrs_define +class FoldersGetPermissionsResponsePermitsItem: + """ + Attributes: + role (str): Content role (e.g., VIEWER, EDITOR, MANAGER) Example: VIEWER. + access_boost (bool | Unset): Whether access boost is enabled for this permit + user_group_id (str | Unset): User group ID if this is a group permit + user_id (UUID | Unset): User ID if this is a user permit + """ + + role: str + access_boost: bool | Unset = UNSET + user_group_id: str | Unset = UNSET + user_id: UUID | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + role = self.role + + access_boost = self.access_boost + + user_group_id = self.user_group_id + + user_id: str | Unset = UNSET + if not isinstance(self.user_id, Unset): + user_id = str(self.user_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "role": role, + } + ) + if access_boost is not UNSET: + field_dict["accessBoost"] = access_boost + if user_group_id is not UNSET: + field_dict["userGroupId"] = user_group_id + if user_id is not UNSET: + field_dict["userId"] = user_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + role = d.pop("role") + + access_boost = d.pop("accessBoost", UNSET) + + user_group_id = d.pop("userGroupId", UNSET) + + _user_id = d.pop("userId", UNSET) + user_id: UUID | Unset + if isinstance(_user_id, Unset): + user_id = UNSET + else: + user_id = UUID(_user_id) + + folders_get_permissions_response_permits_item = cls( + role=role, + access_boost=access_boost, + user_group_id=user_group_id, + user_id=user_id, + ) + + folders_get_permissions_response_permits_item.additional_properties = d + return folders_get_permissions_response_permits_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_list_response.py b/omni_python_sdk/models/folders_list_response.py new file mode 100644 index 0000000..998fc9b --- /dev/null +++ b/omni_python_sdk/models/folders_list_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.folders_list_response_records_item import FoldersListResponseRecordsItem + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="FoldersListResponse") + + +@_attrs_define +class FoldersListResponse: + """ + Attributes: + page_info (PageInfo): + records (list[FoldersListResponseRecordsItem]): List of folders + """ + + page_info: PageInfo + records: list[FoldersListResponseRecordsItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.folders_list_response_records_item import FoldersListResponseRecordsItem + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = FoldersListResponseRecordsItem.from_dict(records_item_data) + + records.append(records_item) + + folders_list_response = cls( + page_info=page_info, + records=records, + ) + + folders_list_response.additional_properties = d + return folders_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_list_response_records_item.py b/omni_python_sdk/models/folders_list_response_records_item.py new file mode 100644 index 0000000..47eaa33 --- /dev/null +++ b/omni_python_sdk/models/folders_list_response_records_item.py @@ -0,0 +1,129 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.folders_list_response_records_item_count import FoldersListResponseRecordsItemCount + + +T = TypeVar("T", bound="FoldersListResponseRecordsItem") + + +@_attrs_define +class FoldersListResponseRecordsItem: + """ + Attributes: + id (UUID): Unique folder identifier + name (str): Name of the folder Example: My Reports. + owner_id (UUID): User ID of the folder owner + path (str): Full path to the folder Example: /shared/reports/my-reports. + url (str): URL to view the folder in the Omni UI. Example: https://org.omni.co/f/my-reports. + field_count (FoldersListResponseRecordsItemCount | Unset): Count statistics for the folder + labels (list[str] | Unset): Labels associated with the folder + """ + + id: UUID + name: str + owner_id: UUID + path: str + url: str + field_count: FoldersListResponseRecordsItemCount | Unset = UNSET + labels: list[str] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + name = self.name + + owner_id = str(self.owner_id) + + path = self.path + + url = self.url + + field_count: dict[str, Any] | Unset = UNSET + if not isinstance(self.field_count, Unset): + field_count = self.field_count.to_dict() + + labels: list[str] | Unset = UNSET + if not isinstance(self.labels, Unset): + labels = self.labels + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + "ownerId": owner_id, + "path": path, + "url": url, + } + ) + if field_count is not UNSET: + field_dict["_count"] = field_count + if labels is not UNSET: + field_dict["labels"] = labels + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.folders_list_response_records_item_count import FoldersListResponseRecordsItemCount + + d = dict(src_dict) + id = UUID(d.pop("id")) + + name = d.pop("name") + + owner_id = UUID(d.pop("ownerId")) + + path = d.pop("path") + + url = d.pop("url") + + _field_count = d.pop("_count", UNSET) + field_count: FoldersListResponseRecordsItemCount | Unset + if isinstance(_field_count, Unset): + field_count = UNSET + else: + field_count = FoldersListResponseRecordsItemCount.from_dict(_field_count) + + labels = cast(list[str], d.pop("labels", UNSET)) + + folders_list_response_records_item = cls( + id=id, + name=name, + owner_id=owner_id, + path=path, + url=url, + field_count=field_count, + labels=labels, + ) + + folders_list_response_records_item.additional_properties = d + return folders_list_response_records_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_list_response_records_item_count.py b/omni_python_sdk/models/folders_list_response_records_item_count.py new file mode 100644 index 0000000..182448f --- /dev/null +++ b/omni_python_sdk/models/folders_list_response_records_item_count.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="FoldersListResponseRecordsItemCount") + + +@_attrs_define +class FoldersListResponseRecordsItemCount: + """Count statistics for the folder + + Attributes: + documents (float): Number of documents in the folder + favorites (float): Number of users who have favorited this folder + """ + + documents: float + favorites: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + documents = self.documents + + favorites = self.favorites + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "documents": documents, + "favorites": favorites, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + documents = d.pop("documents") + + favorites = d.pop("favorites") + + folders_list_response_records_item_count = cls( + documents=documents, + favorites=favorites, + ) + + folders_list_response_records_item_count.additional_properties = d + return folders_list_response_records_item_count + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_list_scope.py b/omni_python_sdk/models/folders_list_scope.py new file mode 100644 index 0000000..7bdb84d --- /dev/null +++ b/omni_python_sdk/models/folders_list_scope.py @@ -0,0 +1,14 @@ +from typing import Literal + +FoldersListScope = Literal["organization", "restricted"] + +FOLDERS_LIST_SCOPE_VALUES: set[FoldersListScope] = { + "organization", + "restricted", +} + + +def check_folders_list_scope(value: str) -> FoldersListScope: + if value in FOLDERS_LIST_SCOPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {FOLDERS_LIST_SCOPE_VALUES!r}") diff --git a/omni_python_sdk/models/folders_list_sort_direction.py b/omni_python_sdk/models/folders_list_sort_direction.py new file mode 100644 index 0000000..eaddfff --- /dev/null +++ b/omni_python_sdk/models/folders_list_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +FoldersListSortDirection = Literal["asc", "desc"] + +FOLDERS_LIST_SORT_DIRECTION_VALUES: set[FoldersListSortDirection] = { + "asc", + "desc", +} + + +def check_folders_list_sort_direction(value: str) -> FoldersListSortDirection: + if value in FOLDERS_LIST_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {FOLDERS_LIST_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/folders_list_sort_field.py b/omni_python_sdk/models/folders_list_sort_field.py new file mode 100644 index 0000000..5ade82b --- /dev/null +++ b/omni_python_sdk/models/folders_list_sort_field.py @@ -0,0 +1,17 @@ +from typing import Literal + +FoldersListSortField = Literal["createdAt", "favorites", "name", "path", "updatedAt"] + +FOLDERS_LIST_SORT_FIELD_VALUES: set[FoldersListSortField] = { + "createdAt", + "favorites", + "name", + "path", + "updatedAt", +} + + +def check_folders_list_sort_field(value: str) -> FoldersListSortField: + if value in FOLDERS_LIST_SORT_FIELD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {FOLDERS_LIST_SORT_FIELD_VALUES!r}") diff --git a/omni_python_sdk/models/folders_revoke_permissions_body.py b/omni_python_sdk/models/folders_revoke_permissions_body.py new file mode 100644 index 0000000..076c197 --- /dev/null +++ b/omni_python_sdk/models/folders_revoke_permissions_body.py @@ -0,0 +1,66 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="FoldersRevokePermissionsBody") + + +@_attrs_define +class FoldersRevokePermissionsBody: + """ + Attributes: + user_group_ids (list[str] | Unset): User group IDs to revoke permissions from + user_ids (list[UUID] | Unset): User IDs to revoke permissions from + """ + + user_group_ids: list[str] | Unset = UNSET + user_ids: list[UUID] | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + user_group_ids: list[str] | Unset = UNSET + if not isinstance(self.user_group_ids, Unset): + user_group_ids = self.user_group_ids + + user_ids: list[str] | Unset = UNSET + if not isinstance(self.user_ids, Unset): + user_ids = [] + for user_ids_item_data in self.user_ids: + user_ids_item = str(user_ids_item_data) + user_ids.append(user_ids_item) + + field_dict: dict[str, Any] = {} + + field_dict.update({}) + if user_group_ids is not UNSET: + field_dict["userGroupIds"] = user_group_ids + if user_ids is not UNSET: + field_dict["userIds"] = user_ids + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + user_group_ids = cast(list[str], d.pop("userGroupIds", UNSET)) + + _user_ids = d.pop("userIds", UNSET) + user_ids: list[UUID] | Unset = UNSET + if _user_ids is not UNSET: + user_ids = [] + for user_ids_item_data in _user_ids: + user_ids_item = UUID(user_ids_item_data) + + user_ids.append(user_ids_item) + + folders_revoke_permissions_body = cls( + user_group_ids=user_group_ids, + user_ids=user_ids, + ) + + return folders_revoke_permissions_body diff --git a/omni_python_sdk/models/folders_revoke_permissions_response.py b/omni_python_sdk/models/folders_revoke_permissions_response.py new file mode 100644 index 0000000..3cecc60 --- /dev/null +++ b/omni_python_sdk/models/folders_revoke_permissions_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="FoldersRevokePermissionsResponse") + + +@_attrs_define +class FoldersRevokePermissionsResponse: + """ + Attributes: + success (bool): Whether the permissions were revoked successfully + """ + + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + success = d.pop("success") + + folders_revoke_permissions_response = cls( + success=success, + ) + + folders_revoke_permissions_response.additional_properties = d + return folders_revoke_permissions_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_update_body.py b/omni_python_sdk/models/folders_update_body.py new file mode 100644 index 0000000..de5646e --- /dev/null +++ b/omni_python_sdk/models/folders_update_body.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="FoldersUpdateBody") + + +@_attrs_define +class FoldersUpdateBody: + """ + Attributes: + name (str | Unset): New display name for the folder Example: Q1 Reports. + path (str | Unset): New URL path segment for the folder (alphanumeric and dashes only). This is only the + folder's own segment, not the full hierarchical path. Example: q1-reports. + resolve_path_conflict (bool | Unset): When true, automatically resolves path collisions with existing folders by + appending a numeric suffix (e.g., my-path-1). When false (default), returns 409 Conflict if the path is already + taken. Does not apply to reserved paths, which are always rejected with 400. Default: False. + """ + + name: str | Unset = UNSET + path: str | Unset = UNSET + resolve_path_conflict: bool | Unset = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + path = self.path + + resolve_path_conflict = self.resolve_path_conflict + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if name is not UNSET: + field_dict["name"] = name + if path is not UNSET: + field_dict["path"] = path + if resolve_path_conflict is not UNSET: + field_dict["resolvePathConflict"] = resolve_path_conflict + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + name = d.pop("name", UNSET) + + path = d.pop("path", UNSET) + + resolve_path_conflict = d.pop("resolvePathConflict", UNSET) + + folders_update_body = cls( + name=name, + path=path, + resolve_path_conflict=resolve_path_conflict, + ) + + folders_update_body.additional_properties = d + return folders_update_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_update_permissions_body.py b/omni_python_sdk/models/folders_update_permissions_body.py new file mode 100644 index 0000000..3b57f03 --- /dev/null +++ b/omni_python_sdk/models/folders_update_permissions_body.py @@ -0,0 +1,95 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define + +from ..models.folders_update_permissions_body_role import ( + FoldersUpdatePermissionsBodyRole, + check_folders_update_permissions_body_role, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="FoldersUpdatePermissionsBody") + + +@_attrs_define +class FoldersUpdatePermissionsBody: + """ + Attributes: + access_boost (bool | Unset): Whether to grant access boost + role (FoldersUpdatePermissionsBodyRole | Unset): New content role to assign + user_group_ids (list[str] | Unset): User group IDs to update permissions for + user_ids (list[UUID] | Unset): User IDs to update permissions for + """ + + access_boost: bool | Unset = UNSET + role: FoldersUpdatePermissionsBodyRole | Unset = UNSET + user_group_ids: list[str] | Unset = UNSET + user_ids: list[UUID] | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + access_boost = self.access_boost + + role: str | Unset = UNSET + if not isinstance(self.role, Unset): + role = self.role + + user_group_ids: list[str] | Unset = UNSET + if not isinstance(self.user_group_ids, Unset): + user_group_ids = self.user_group_ids + + user_ids: list[str] | Unset = UNSET + if not isinstance(self.user_ids, Unset): + user_ids = [] + for user_ids_item_data in self.user_ids: + user_ids_item = str(user_ids_item_data) + user_ids.append(user_ids_item) + + field_dict: dict[str, Any] = {} + + field_dict.update({}) + if access_boost is not UNSET: + field_dict["accessBoost"] = access_boost + if role is not UNSET: + field_dict["role"] = role + if user_group_ids is not UNSET: + field_dict["userGroupIds"] = user_group_ids + if user_ids is not UNSET: + field_dict["userIds"] = user_ids + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + access_boost = d.pop("accessBoost", UNSET) + + _role = d.pop("role", UNSET) + role: FoldersUpdatePermissionsBodyRole | Unset + if isinstance(_role, Unset): + role = UNSET + else: + role = check_folders_update_permissions_body_role(_role) + + user_group_ids = cast(list[str], d.pop("userGroupIds", UNSET)) + + _user_ids = d.pop("userIds", UNSET) + user_ids: list[UUID] | Unset = UNSET + if _user_ids is not UNSET: + user_ids = [] + for user_ids_item_data in _user_ids: + user_ids_item = UUID(user_ids_item_data) + + user_ids.append(user_ids_item) + + folders_update_permissions_body = cls( + access_boost=access_boost, + role=role, + user_group_ids=user_group_ids, + user_ids=user_ids, + ) + + return folders_update_permissions_body diff --git a/omni_python_sdk/models/folders_update_permissions_body_role.py b/omni_python_sdk/models/folders_update_permissions_body_role.py new file mode 100644 index 0000000..1f6cc20 --- /dev/null +++ b/omni_python_sdk/models/folders_update_permissions_body_role.py @@ -0,0 +1,17 @@ +from typing import Literal + +FoldersUpdatePermissionsBodyRole = Literal["EDITOR", "EXPLORER", "MANAGER", "NO_ACCESS", "VIEWER"] + +FOLDERS_UPDATE_PERMISSIONS_BODY_ROLE_VALUES: set[FoldersUpdatePermissionsBodyRole] = { + "EDITOR", + "EXPLORER", + "MANAGER", + "NO_ACCESS", + "VIEWER", +} + + +def check_folders_update_permissions_body_role(value: str) -> FoldersUpdatePermissionsBodyRole: + if value in FOLDERS_UPDATE_PERMISSIONS_BODY_ROLE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {FOLDERS_UPDATE_PERMISSIONS_BODY_ROLE_VALUES!r}") diff --git a/omni_python_sdk/models/folders_update_permissions_response.py b/omni_python_sdk/models/folders_update_permissions_response.py new file mode 100644 index 0000000..d2f351f --- /dev/null +++ b/omni_python_sdk/models/folders_update_permissions_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="FoldersUpdatePermissionsResponse") + + +@_attrs_define +class FoldersUpdatePermissionsResponse: + """ + Attributes: + success (bool): Whether the permissions were updated successfully + """ + + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + success = d.pop("success") + + folders_update_permissions_response = cls( + success=success, + ) + + folders_update_permissions_response.additional_properties = d + return folders_update_permissions_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/folders_update_response.py b/omni_python_sdk/models/folders_update_response.py new file mode 100644 index 0000000..ffd7fd7 --- /dev/null +++ b/omni_python_sdk/models/folders_update_response.py @@ -0,0 +1,78 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="FoldersUpdateResponse") + + +@_attrs_define +class FoldersUpdateResponse: + """ + Attributes: + id (UUID): Folder ID + name (str): Updated folder name + path (str): Updated URL path segment for the folder (the folder's own segment only) + """ + + id: UUID + name: str + path: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + name = self.name + + path = self.path + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + "path": path, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = UUID(d.pop("id")) + + name = d.pop("name") + + path = d.pop("path") + + folders_update_response = cls( + id=id, + name=name, + path=path, + ) + + folders_update_response.additional_properties = d + return folders_update_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/grid_container.py b/omni_python_sdk/models/grid_container.py new file mode 100644 index 0000000..a06a551 --- /dev/null +++ b/omni_python_sdk/models/grid_container.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="GridContainer") + + +@_attrs_define +class GridContainer: + """Grid container — children are positioned on a grid (each carries a gridPosition). (Not statically modeled; use plain + dicts.) + + """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + grid_container = cls() + + grid_container.additional_properties = d + return grid_container + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ignore_suggestion_body.py b/omni_python_sdk/models/ignore_suggestion_body.py new file mode 100644 index 0000000..fe0fdeb --- /dev/null +++ b/omni_python_sdk/models/ignore_suggestion_body.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="IgnoreSuggestionBody") + + +@_attrs_define +class IgnoreSuggestionBody: + """ + Attributes: + reason (str | Unset): Optional free-text reason for dismissing the suggestion. Example: Already covered by an + existing field description.. + """ + + reason: str | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + reason = self.reason + + field_dict: dict[str, Any] = {} + + field_dict.update({}) + if reason is not UNSET: + field_dict["reason"] = reason + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + reason = d.pop("reason", UNSET) + + ignore_suggestion_body = cls( + reason=reason, + ) + + return ignore_suggestion_body diff --git a/omni_python_sdk/models/internal_folder_type_0.py b/omni_python_sdk/models/internal_folder_type_0.py new file mode 100644 index 0000000..fe41056 --- /dev/null +++ b/omni_python_sdk/models/internal_folder_type_0.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.content_share_scope import ContentShareScope, check_content_share_scope + +T = TypeVar("T", bound="InternalFolderType0") + + +@_attrs_define +class InternalFolderType0: + """Parent folder + + Attributes: + id (str): Folder ID + name (str): Folder name + path (str): Folder path + scope (ContentShareScope): Content access scope + """ + + id: str + name: str + path: str + scope: ContentShareScope + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + path = self.path + + scope: str = self.scope + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + "path": path, + "scope": scope, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + name = d.pop("name") + + path = d.pop("path") + + scope = check_content_share_scope(d.pop("scope")) + + internal_folder_type_0 = cls( + id=id, + name=name, + path=path, + scope=scope, + ) + + internal_folder_type_0.additional_properties = d + return internal_folder_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/job_created_response.py b/omni_python_sdk/models/job_created_response.py new file mode 100644 index 0000000..c304c29 --- /dev/null +++ b/omni_python_sdk/models/job_created_response.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="JobCreatedResponse") + + +@_attrs_define +class JobCreatedResponse: + """ + Attributes: + job_id (str): ID of the created job. Poll GET /api/v1/jobs/{jobId}/status for its status. Example: + 550e8400-e29b-41d4-a716-446655440000. + """ + + job_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + job_id = self.job_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "jobId": job_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + job_id = d.pop("jobId") + + job_created_response = cls( + job_id=job_id, + ) + + job_created_response.additional_properties = d + return job_created_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/jobs_get_status_response.py b/omni_python_sdk/models/jobs_get_status_response.py new file mode 100644 index 0000000..84a8249 --- /dev/null +++ b/omni_python_sdk/models/jobs_get_status_response.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.jobs_get_status_response_status import JobsGetStatusResponseStatus, check_jobs_get_status_response_status + +T = TypeVar("T", bound="JobsGetStatusResponse") + + +@_attrs_define +class JobsGetStatusResponse: + """ + Attributes: + job_id (str): The job ID Example: 550e8400-e29b-41d4-a716-446655440000. + job_type (str): The type of job (e.g., REFRESH_SCHEMA) Example: REFRESH_SCHEMA. + status (JobsGetStatusResponseStatus): Current status of the job Example: COMPLETED. + """ + + job_id: str + job_type: str + status: JobsGetStatusResponseStatus + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + job_id = self.job_id + + job_type = self.job_type + + status: str = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "job_id": job_id, + "job_type": job_type, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + job_id = d.pop("job_id") + + job_type = d.pop("job_type") + + status = check_jobs_get_status_response_status(d.pop("status")) + + jobs_get_status_response = cls( + job_id=job_id, + job_type=job_type, + status=status, + ) + + jobs_get_status_response.additional_properties = d + return jobs_get_status_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/jobs_get_status_response_status.py b/omni_python_sdk/models/jobs_get_status_response_status.py new file mode 100644 index 0000000..be3dbb5 --- /dev/null +++ b/omni_python_sdk/models/jobs_get_status_response_status.py @@ -0,0 +1,15 @@ +from typing import Literal + +JobsGetStatusResponseStatus = Literal["COMPLETED", "FAILED", "IN_PROGRESS"] + +JOBS_GET_STATUS_RESPONSE_STATUS_VALUES: set[JobsGetStatusResponseStatus] = { + "COMPLETED", + "FAILED", + "IN_PROGRESS", +} + + +def check_jobs_get_status_response_status(value: str) -> JobsGetStatusResponseStatus: + if value in JOBS_GET_STATUS_RESPONSE_STATUS_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {JOBS_GET_STATUS_RESPONSE_STATUS_VALUES!r}") diff --git a/omni_python_sdk/models/json_value.py b/omni_python_sdk/models/json_value.py new file mode 100644 index 0000000..91b0a19 --- /dev/null +++ b/omni_python_sdk/models/json_value.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="JsonValue") + + +@_attrs_define +class JsonValue: + """Arbitrary JSON value (string, number, boolean, null, object, or array). (Not statically modeled; use plain dicts.)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + json_value = cls() + + json_value.additional_properties = d + return json_value + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/labels_create_body.py b/omni_python_sdk/models/labels_create_body.py new file mode 100644 index 0000000..9a9b140 --- /dev/null +++ b/omni_python_sdk/models/labels_create_body.py @@ -0,0 +1,121 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="LabelsCreateBody") + + +@_attrs_define +class LabelsCreateBody: + """ + Attributes: + name (str): Label name Example: important. + color (None | str | Unset): Hex color for the label (e.g. #0366d6) Example: #0366d6. + description (None | str | Unset): Label description Example: Important items that need attention. + homepage (bool | Unset): Show label on homepage. Requires admin permissions. Default: False. + verified (bool | Unset): Mark as verified label. Requires admin permissions. Default: False. + """ + + name: str + color: None | str | Unset = UNSET + description: None | str | Unset = UNSET + homepage: bool | Unset = False + verified: bool | Unset = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + color: None | str | Unset + if isinstance(self.color, Unset): + color = UNSET + else: + color = self.color + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + homepage = self.homepage + + verified = self.verified + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + if color is not UNSET: + field_dict["color"] = color + if description is not UNSET: + field_dict["description"] = description + if homepage is not UNSET: + field_dict["homepage"] = homepage + if verified is not UNSET: + field_dict["verified"] = verified + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + name = d.pop("name") + + def _parse_color(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + color = _parse_color(d.pop("color", UNSET)) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + homepage = d.pop("homepage", UNSET) + + verified = d.pop("verified", UNSET) + + labels_create_body = cls( + name=name, + color=color, + description=description, + homepage=homepage, + verified=verified, + ) + + labels_create_body.additional_properties = d + return labels_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/labels_create_response.py b/omni_python_sdk/models/labels_create_response.py new file mode 100644 index 0000000..315bd33 --- /dev/null +++ b/omni_python_sdk/models/labels_create_response.py @@ -0,0 +1,114 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="LabelsCreateResponse") + + +@_attrs_define +class LabelsCreateResponse: + """ + Attributes: + color (None | str): Hex color for the label (e.g. #0366d6) Example: #0366d6. + description (None | str): Label description Example: Important items that need attention. + homepage (bool): Whether label is shown on homepage + name (str): Label name Example: verified. + usage_count (float): Number of documents with this label + verified (bool): Whether label is verified + """ + + color: None | str + description: None | str + homepage: bool + name: str + usage_count: float + verified: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + color: None | str + color = self.color + + description: None | str + description = self.description + + homepage = self.homepage + + name = self.name + + usage_count = self.usage_count + + verified = self.verified + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "color": color, + "description": description, + "homepage": homepage, + "name": name, + "usage_count": usage_count, + "verified": verified, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_color(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + color = _parse_color(d.pop("color")) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + homepage = d.pop("homepage") + + name = d.pop("name") + + usage_count = d.pop("usage_count") + + verified = d.pop("verified") + + labels_create_response = cls( + color=color, + description=description, + homepage=homepage, + name=name, + usage_count=usage_count, + verified=verified, + ) + + labels_create_response.additional_properties = d + return labels_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/labels_get_response.py b/omni_python_sdk/models/labels_get_response.py new file mode 100644 index 0000000..ecef468 --- /dev/null +++ b/omni_python_sdk/models/labels_get_response.py @@ -0,0 +1,114 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="LabelsGetResponse") + + +@_attrs_define +class LabelsGetResponse: + """ + Attributes: + color (None | str): Hex color for the label (e.g. #0366d6) Example: #0366d6. + description (None | str): Label description Example: Important items that need attention. + homepage (bool): Whether label is shown on homepage + name (str): Label name Example: verified. + usage_count (float): Number of documents with this label + verified (bool): Whether label is verified + """ + + color: None | str + description: None | str + homepage: bool + name: str + usage_count: float + verified: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + color: None | str + color = self.color + + description: None | str + description = self.description + + homepage = self.homepage + + name = self.name + + usage_count = self.usage_count + + verified = self.verified + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "color": color, + "description": description, + "homepage": homepage, + "name": name, + "usage_count": usage_count, + "verified": verified, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_color(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + color = _parse_color(d.pop("color")) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + homepage = d.pop("homepage") + + name = d.pop("name") + + usage_count = d.pop("usage_count") + + verified = d.pop("verified") + + labels_get_response = cls( + color=color, + description=description, + homepage=homepage, + name=name, + usage_count=usage_count, + verified=verified, + ) + + labels_get_response.additional_properties = d + return labels_get_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/labels_list_response.py b/omni_python_sdk/models/labels_list_response.py new file mode 100644 index 0000000..64cb35e --- /dev/null +++ b/omni_python_sdk/models/labels_list_response.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.labels_list_response_labels_item import LabelsListResponseLabelsItem + + +T = TypeVar("T", bound="LabelsListResponse") + + +@_attrs_define +class LabelsListResponse: + """ + Attributes: + labels (list[LabelsListResponseLabelsItem]): List of labels + """ + + labels: list[LabelsListResponseLabelsItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + labels = [] + for labels_item_data in self.labels: + labels_item = labels_item_data.to_dict() + labels.append(labels_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "labels": labels, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.labels_list_response_labels_item import LabelsListResponseLabelsItem + + d = dict(src_dict) + labels = [] + _labels = d.pop("labels") + for labels_item_data in _labels: + labels_item = LabelsListResponseLabelsItem.from_dict(labels_item_data) + + labels.append(labels_item) + + labels_list_response = cls( + labels=labels, + ) + + labels_list_response.additional_properties = d + return labels_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/labels_list_response_labels_item.py b/omni_python_sdk/models/labels_list_response_labels_item.py new file mode 100644 index 0000000..5a07edf --- /dev/null +++ b/omni_python_sdk/models/labels_list_response_labels_item.py @@ -0,0 +1,114 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="LabelsListResponseLabelsItem") + + +@_attrs_define +class LabelsListResponseLabelsItem: + """ + Attributes: + color (None | str): Hex color for the label (e.g. #0366d6) Example: #0366d6. + description (None | str): Label description Example: Important items that need attention. + homepage (bool): Whether label is shown on homepage + name (str): Label name Example: verified. + usage_count (float): Number of documents with this label + verified (bool): Whether label is verified + """ + + color: None | str + description: None | str + homepage: bool + name: str + usage_count: float + verified: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + color: None | str + color = self.color + + description: None | str + description = self.description + + homepage = self.homepage + + name = self.name + + usage_count = self.usage_count + + verified = self.verified + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "color": color, + "description": description, + "homepage": homepage, + "name": name, + "usage_count": usage_count, + "verified": verified, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_color(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + color = _parse_color(d.pop("color")) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + homepage = d.pop("homepage") + + name = d.pop("name") + + usage_count = d.pop("usage_count") + + verified = d.pop("verified") + + labels_list_response_labels_item = cls( + color=color, + description=description, + homepage=homepage, + name=name, + usage_count=usage_count, + verified=verified, + ) + + labels_list_response_labels_item.additional_properties = d + return labels_list_response_labels_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/labels_update_body.py b/omni_python_sdk/models/labels_update_body.py new file mode 100644 index 0000000..010581a --- /dev/null +++ b/omni_python_sdk/models/labels_update_body.py @@ -0,0 +1,120 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="LabelsUpdateBody") + + +@_attrs_define +class LabelsUpdateBody: + """ + Attributes: + color (None | str | Unset): Hex color for the label (e.g. #0366d6) Example: #0366d6. + description (None | str | Unset): Label description Example: Important items that need attention. + homepage (bool | Unset): Show label on homepage. Requires admin permissions to modify. + name (str | Unset): Label name Example: important. + verified (bool | Unset): Mark as verified label. Requires admin permissions to modify. + """ + + color: None | str | Unset = UNSET + description: None | str | Unset = UNSET + homepage: bool | Unset = UNSET + name: str | Unset = UNSET + verified: bool | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + color: None | str | Unset + if isinstance(self.color, Unset): + color = UNSET + else: + color = self.color + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + homepage = self.homepage + + name = self.name + + verified = self.verified + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if color is not UNSET: + field_dict["color"] = color + if description is not UNSET: + field_dict["description"] = description + if homepage is not UNSET: + field_dict["homepage"] = homepage + if name is not UNSET: + field_dict["name"] = name + if verified is not UNSET: + field_dict["verified"] = verified + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_color(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + color = _parse_color(d.pop("color", UNSET)) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + homepage = d.pop("homepage", UNSET) + + name = d.pop("name", UNSET) + + verified = d.pop("verified", UNSET) + + labels_update_body = cls( + color=color, + description=description, + homepage=homepage, + name=name, + verified=verified, + ) + + labels_update_body.additional_properties = d + return labels_update_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/labels_update_response.py b/omni_python_sdk/models/labels_update_response.py new file mode 100644 index 0000000..a7118b6 --- /dev/null +++ b/omni_python_sdk/models/labels_update_response.py @@ -0,0 +1,114 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="LabelsUpdateResponse") + + +@_attrs_define +class LabelsUpdateResponse: + """ + Attributes: + color (None | str): Hex color for the label (e.g. #0366d6) Example: #0366d6. + description (None | str): Label description Example: Important items that need attention. + homepage (bool): Whether label is shown on homepage + name (str): Label name Example: verified. + usage_count (float): Number of documents with this label + verified (bool): Whether label is verified + """ + + color: None | str + description: None | str + homepage: bool + name: str + usage_count: float + verified: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + color: None | str + color = self.color + + description: None | str + description = self.description + + homepage = self.homepage + + name = self.name + + usage_count = self.usage_count + + verified = self.verified + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "color": color, + "description": description, + "homepage": homepage, + "name": name, + "usage_count": usage_count, + "verified": verified, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_color(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + color = _parse_color(d.pop("color")) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + homepage = d.pop("homepage") + + name = d.pop("name") + + usage_count = d.pop("usage_count") + + verified = d.pop("verified") + + labels_update_response = cls( + color=color, + description=description, + homepage=homepage, + name=name, + usage_count=usage_count, + verified=verified, + ) + + labels_update_response.additional_properties = d + return labels_update_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/model_suggestion.py b/omni_python_sdk/models/model_suggestion.py new file mode 100644 index 0000000..bbbd1ce --- /dev/null +++ b/omni_python_sdk/models/model_suggestion.py @@ -0,0 +1,235 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.suggestion_evidence_item import SuggestionEvidenceItem + from ..models.suggestion_proposed_changes import SuggestionProposedChanges + + +T = TypeVar("T", bound="ModelSuggestion") + + +@_attrs_define +class ModelSuggestion: + """ + Attributes: + ai_modified_at (datetime.datetime): ISO 8601 timestamp of the last AI write (create or AI update). Unaffected by + dismiss/restore. + category (str): Suggestion category, e.g. `missing_context`. Example: missing_context. + created_at (datetime.datetime): ISO 8601 timestamp of when the suggestion was created. + evidence (list[SuggestionEvidenceItem] | None): Source evidence for the suggestion. Null for rows created before + evidence was tracked; `[]` when none was cited. + id (UUID): Unique identifier for the suggestion. + ignore_reason (None | str): Optional free-text reason recorded when the suggestion was dismissed. + ignored_at (datetime.datetime | None): ISO 8601 timestamp of dismissal, or null if active. + ignored_by (None | UUID): User id that dismissed the suggestion, or null if active. + priority (int): Priority from 1 (highest) to 10 (lowest). Example: 1. + proposed_changes (SuggestionProposedChanges): The change(s) the suggestion would apply to the model. + rationale (str): Explanation of why the suggestion was made. + title (str): Short human-readable title. + updated_at (datetime.datetime): ISO 8601 timestamp of the last write of any kind, including dismiss/restore. + """ + + ai_modified_at: datetime.datetime + category: str + created_at: datetime.datetime + evidence: list[SuggestionEvidenceItem] | None + id: UUID + ignore_reason: None | str + ignored_at: datetime.datetime | None + ignored_by: None | UUID + priority: int + proposed_changes: SuggestionProposedChanges + rationale: str + title: str + updated_at: datetime.datetime + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + ai_modified_at = self.ai_modified_at.isoformat() + + category = self.category + + created_at = self.created_at.isoformat() + + evidence: list[dict[str, Any]] | None + if isinstance(self.evidence, list): + evidence = [] + for evidence_type_0_item_data in self.evidence: + evidence_type_0_item = evidence_type_0_item_data.to_dict() + evidence.append(evidence_type_0_item) + + else: + evidence = self.evidence + + id = str(self.id) + + ignore_reason: None | str + ignore_reason = self.ignore_reason + + ignored_at: None | str + if isinstance(self.ignored_at, datetime.datetime): + ignored_at = self.ignored_at.isoformat() + else: + ignored_at = self.ignored_at + + ignored_by: None | str + if isinstance(self.ignored_by, UUID): + ignored_by = str(self.ignored_by) + else: + ignored_by = self.ignored_by + + priority = self.priority + + proposed_changes = self.proposed_changes.to_dict() + + rationale = self.rationale + + title = self.title + + updated_at = self.updated_at.isoformat() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "aiModifiedAt": ai_modified_at, + "category": category, + "createdAt": created_at, + "evidence": evidence, + "id": id, + "ignoreReason": ignore_reason, + "ignoredAt": ignored_at, + "ignoredBy": ignored_by, + "priority": priority, + "proposedChanges": proposed_changes, + "rationale": rationale, + "title": title, + "updatedAt": updated_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.suggestion_evidence_item import SuggestionEvidenceItem + from ..models.suggestion_proposed_changes import SuggestionProposedChanges + + d = dict(src_dict) + ai_modified_at = datetime.datetime.fromisoformat(d.pop("aiModifiedAt")) + + category = d.pop("category") + + created_at = datetime.datetime.fromisoformat(d.pop("createdAt")) + + def _parse_evidence(data: object) -> list[SuggestionEvidenceItem] | None: + if data is None: + return data + try: + if not isinstance(data, list): + raise TypeError() + evidence_type_0 = [] + _evidence_type_0 = data + for evidence_type_0_item_data in _evidence_type_0: + evidence_type_0_item = SuggestionEvidenceItem.from_dict(evidence_type_0_item_data) + + evidence_type_0.append(evidence_type_0_item) + + return evidence_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(list[SuggestionEvidenceItem] | None, data) + + evidence = _parse_evidence(d.pop("evidence")) + + id = UUID(d.pop("id")) + + def _parse_ignore_reason(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + ignore_reason = _parse_ignore_reason(d.pop("ignoreReason")) + + def _parse_ignored_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + ignored_at_type_0 = datetime.datetime.fromisoformat(data) + + return ignored_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + ignored_at = _parse_ignored_at(d.pop("ignoredAt")) + + def _parse_ignored_by(data: object) -> None | UUID: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + ignored_by_type_0 = UUID(data) + + return ignored_by_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UUID, data) + + ignored_by = _parse_ignored_by(d.pop("ignoredBy")) + + priority = d.pop("priority") + + proposed_changes = SuggestionProposedChanges.from_dict(d.pop("proposedChanges")) + + rationale = d.pop("rationale") + + title = d.pop("title") + + updated_at = datetime.datetime.fromisoformat(d.pop("updatedAt")) + + model_suggestion = cls( + ai_modified_at=ai_modified_at, + category=category, + created_at=created_at, + evidence=evidence, + id=id, + ignore_reason=ignore_reason, + ignored_at=ignored_at, + ignored_by=ignored_by, + priority=priority, + proposed_changes=proposed_changes, + rationale=rationale, + title=title, + updated_at=updated_at, + ) + + model_suggestion.additional_properties = d + return model_suggestion + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/model_suggestions_list_response.py b/omni_python_sdk/models/model_suggestions_list_response.py new file mode 100644 index 0000000..cd2da0d --- /dev/null +++ b/omni_python_sdk/models/model_suggestions_list_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.model_suggestion import ModelSuggestion + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="ModelSuggestionsListResponse") + + +@_attrs_define +class ModelSuggestionsListResponse: + """ + Attributes: + page_info (PageInfo): + records (list[ModelSuggestion]): + """ + + page_info: PageInfo + records: list[ModelSuggestion] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.model_suggestion import ModelSuggestion + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = ModelSuggestion.from_dict(records_item_data) + + records.append(records_item) + + model_suggestions_list_response = cls( + page_info=page_info, + records=records, + ) + + model_suggestions_list_response.additional_properties = d + return model_suggestions_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/model_suggestions_list_status.py b/omni_python_sdk/models/model_suggestions_list_status.py new file mode 100644 index 0000000..4e89aa7 --- /dev/null +++ b/omni_python_sdk/models/model_suggestions_list_status.py @@ -0,0 +1,15 @@ +from typing import Literal + +ModelSuggestionsListStatus = Literal["active", "all", "ignored"] + +MODEL_SUGGESTIONS_LIST_STATUS_VALUES: set[ModelSuggestionsListStatus] = { + "active", + "all", + "ignored", +} + + +def check_model_suggestions_list_status(value: str) -> ModelSuggestionsListStatus: + if value in MODEL_SUGGESTIONS_LIST_STATUS_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODEL_SUGGESTIONS_LIST_STATUS_VALUES!r}") diff --git a/omni_python_sdk/models/model_yaml_create_request_body.py b/omni_python_sdk/models/model_yaml_create_request_body.py new file mode 100644 index 0000000..fb96e88 --- /dev/null +++ b/omni_python_sdk/models/model_yaml_create_request_body.py @@ -0,0 +1,126 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define + +from ..models.model_yaml_create_request_body_mode import ( + ModelYamlCreateRequestBodyMode, + check_model_yaml_create_request_body_mode, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelYamlCreateRequestBody") + + +@_attrs_define +class ModelYamlCreateRequestBody: + """ + Attributes: + file_name (str): File name to create or update + yaml (str): YAML content for the file + branch_id (UUID | Unset): Branch ID for branch-aware operations + mode (ModelYamlCreateRequestBodyMode | Unset): IDE mode for YAML operations Default: 'combined'. + commit_message (str | Unset): Commit message for git sync + fetched_at_millis (float | Unset): Timestamp when the file was fetched + fully_resolved (bool | Unset): Treat the posted YAML as fully resolved (with the extends chain expanded). Only + valid with mode=combined. Default: False. + previous_checksum (str | Unset): Previous checksum for conflict detection + """ + + file_name: str + yaml: str + branch_id: UUID | Unset = UNSET + mode: ModelYamlCreateRequestBodyMode | Unset = "combined" + commit_message: str | Unset = UNSET + fetched_at_millis: float | Unset = UNSET + fully_resolved: bool | Unset = False + previous_checksum: str | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + file_name = self.file_name + + yaml = self.yaml + + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + mode: str | Unset = UNSET + if not isinstance(self.mode, Unset): + mode = self.mode + + commit_message = self.commit_message + + fetched_at_millis = self.fetched_at_millis + + fully_resolved = self.fully_resolved + + previous_checksum = self.previous_checksum + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "fileName": file_name, + "yaml": yaml, + } + ) + if branch_id is not UNSET: + field_dict["branchId"] = branch_id + if mode is not UNSET: + field_dict["mode"] = mode + if commit_message is not UNSET: + field_dict["commitMessage"] = commit_message + if fetched_at_millis is not UNSET: + field_dict["fetchedAtMillis"] = fetched_at_millis + if fully_resolved is not UNSET: + field_dict["fullyResolved"] = fully_resolved + if previous_checksum is not UNSET: + field_dict["previousChecksum"] = previous_checksum + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + file_name = d.pop("fileName") + + yaml = d.pop("yaml") + + _branch_id = d.pop("branchId", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + _mode = d.pop("mode", UNSET) + mode: ModelYamlCreateRequestBodyMode | Unset + if isinstance(_mode, Unset): + mode = UNSET + else: + mode = check_model_yaml_create_request_body_mode(_mode) + + commit_message = d.pop("commitMessage", UNSET) + + fetched_at_millis = d.pop("fetchedAtMillis", UNSET) + + fully_resolved = d.pop("fullyResolved", UNSET) + + previous_checksum = d.pop("previousChecksum", UNSET) + + model_yaml_create_request_body = cls( + file_name=file_name, + yaml=yaml, + branch_id=branch_id, + mode=mode, + commit_message=commit_message, + fetched_at_millis=fetched_at_millis, + fully_resolved=fully_resolved, + previous_checksum=previous_checksum, + ) + + return model_yaml_create_request_body diff --git a/omni_python_sdk/models/model_yaml_create_request_body_mode.py b/omni_python_sdk/models/model_yaml_create_request_body_mode.py new file mode 100644 index 0000000..c9219ce --- /dev/null +++ b/omni_python_sdk/models/model_yaml_create_request_body_mode.py @@ -0,0 +1,17 @@ +from typing import Literal + +ModelYamlCreateRequestBodyMode = Literal["combined", "extension", "fully-resolved", "merged", "staged"] + +MODEL_YAML_CREATE_REQUEST_BODY_MODE_VALUES: set[ModelYamlCreateRequestBodyMode] = { + "combined", + "extension", + "fully-resolved", + "merged", + "staged", +} + + +def check_model_yaml_create_request_body_mode(value: str) -> ModelYamlCreateRequestBodyMode: + if value in MODEL_YAML_CREATE_REQUEST_BODY_MODE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODEL_YAML_CREATE_REQUEST_BODY_MODE_VALUES!r}") diff --git a/omni_python_sdk/models/model_yaml_response.py b/omni_python_sdk/models/model_yaml_response.py new file mode 100644 index 0000000..37a8bde --- /dev/null +++ b/omni_python_sdk/models/model_yaml_response.py @@ -0,0 +1,113 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.model_yaml_response_checksums import ModelYamlResponseChecksums + from ..models.model_yaml_response_files import ModelYamlResponseFiles + from ..models.model_yaml_response_view_names import ModelYamlResponseViewNames + + +T = TypeVar("T", bound="ModelYamlResponse") + + +@_attrs_define +class ModelYamlResponse: + """ + Attributes: + files (ModelYamlResponseFiles): YAML content for each file + version (float): Model version number + checksums (ModelYamlResponseChecksums | Unset): Checksums for each file + view_names (ModelYamlResponseViewNames | Unset): View name mappings + """ + + files: ModelYamlResponseFiles + version: float + checksums: ModelYamlResponseChecksums | Unset = UNSET + view_names: ModelYamlResponseViewNames | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + files = self.files.to_dict() + + version = self.version + + checksums: dict[str, Any] | Unset = UNSET + if not isinstance(self.checksums, Unset): + checksums = self.checksums.to_dict() + + view_names: dict[str, Any] | Unset = UNSET + if not isinstance(self.view_names, Unset): + view_names = self.view_names.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "files": files, + "version": version, + } + ) + if checksums is not UNSET: + field_dict["checksums"] = checksums + if view_names is not UNSET: + field_dict["viewNames"] = view_names + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.model_yaml_response_checksums import ModelYamlResponseChecksums + from ..models.model_yaml_response_files import ModelYamlResponseFiles + from ..models.model_yaml_response_view_names import ModelYamlResponseViewNames + + d = dict(src_dict) + files = ModelYamlResponseFiles.from_dict(d.pop("files")) + + version = d.pop("version") + + _checksums = d.pop("checksums", UNSET) + checksums: ModelYamlResponseChecksums | Unset + if isinstance(_checksums, Unset): + checksums = UNSET + else: + checksums = ModelYamlResponseChecksums.from_dict(_checksums) + + _view_names = d.pop("viewNames", UNSET) + view_names: ModelYamlResponseViewNames | Unset + if isinstance(_view_names, Unset): + view_names = UNSET + else: + view_names = ModelYamlResponseViewNames.from_dict(_view_names) + + model_yaml_response = cls( + files=files, + version=version, + checksums=checksums, + view_names=view_names, + ) + + model_yaml_response.additional_properties = d + return model_yaml_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/model_yaml_response_checksums.py b/omni_python_sdk/models/model_yaml_response_checksums.py new file mode 100644 index 0000000..7593716 --- /dev/null +++ b/omni_python_sdk/models/model_yaml_response_checksums.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelYamlResponseChecksums") + + +@_attrs_define +class ModelYamlResponseChecksums: + """Checksums for each file""" + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + model_yaml_response_checksums = cls() + + model_yaml_response_checksums.additional_properties = d + return model_yaml_response_checksums + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/model_yaml_response_files.py b/omni_python_sdk/models/model_yaml_response_files.py new file mode 100644 index 0000000..4d3c8a0 --- /dev/null +++ b/omni_python_sdk/models/model_yaml_response_files.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelYamlResponseFiles") + + +@_attrs_define +class ModelYamlResponseFiles: + """YAML content for each file""" + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + model_yaml_response_files = cls() + + model_yaml_response_files.additional_properties = d + return model_yaml_response_files + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/model_yaml_response_view_names.py b/omni_python_sdk/models/model_yaml_response_view_names.py new file mode 100644 index 0000000..c8fadaa --- /dev/null +++ b/omni_python_sdk/models/model_yaml_response_view_names.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelYamlResponseViewNames") + + +@_attrs_define +class ModelYamlResponseViewNames: + """View name mappings""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + model_yaml_response_view_names = cls() + + model_yaml_response_view_names.additional_properties = d + return model_yaml_response_view_names + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_branch_dbt_body.py b/omni_python_sdk/models/models_branch_dbt_body.py new file mode 100644 index 0000000..ffc08e9 --- /dev/null +++ b/omni_python_sdk/models/models_branch_dbt_body.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsBranchDbtBody") + + +@_attrs_define +class ModelsBranchDbtBody: + """ + Attributes: + dbt_environment_id (UUID): ID of the dbt environment to activate on this branch Example: + 123e4567-e89b-12d3-a456-426614174000. + dbt_git_branch (str | Unset): Git branch to associate with the dbt environment Example: feature/new-metrics. + """ + + dbt_environment_id: UUID + dbt_git_branch: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + dbt_environment_id = str(self.dbt_environment_id) + + dbt_git_branch = self.dbt_git_branch + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "dbt_environment_id": dbt_environment_id, + } + ) + if dbt_git_branch is not UNSET: + field_dict["dbt_git_branch"] = dbt_git_branch + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + dbt_environment_id = UUID(d.pop("dbt_environment_id")) + + dbt_git_branch = d.pop("dbt_git_branch", UNSET) + + models_branch_dbt_body = cls( + dbt_environment_id=dbt_environment_id, + dbt_git_branch=dbt_git_branch, + ) + + models_branch_dbt_body.additional_properties = d + return models_branch_dbt_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_cache_reset_body.py b/omni_python_sdk/models/models_cache_reset_body.py new file mode 100644 index 0000000..143fa29 --- /dev/null +++ b/omni_python_sdk/models/models_cache_reset_body.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsCacheResetBody") + + +@_attrs_define +class ModelsCacheResetBody: + """ + Attributes: + reset_at (str | Unset): ISO-8601 timestamp for when to reset the cache Example: 2024-01-15T12:00:00Z. + """ + + reset_at: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + reset_at = self.reset_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if reset_at is not UNSET: + field_dict["resetAt"] = reset_at + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + reset_at = d.pop("resetAt", UNSET) + + models_cache_reset_body = cls( + reset_at=reset_at, + ) + + models_cache_reset_body.additional_properties = d + return models_cache_reset_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_cache_reset_response.py b/omni_python_sdk/models/models_cache_reset_response.py new file mode 100644 index 0000000..2354a5d --- /dev/null +++ b/omni_python_sdk/models/models_cache_reset_response.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.models_cache_reset_response_cache_reset import ModelsCacheResetResponseCacheReset + + +T = TypeVar("T", bound="ModelsCacheResetResponse") + + +@_attrs_define +class ModelsCacheResetResponse: + """ + Attributes: + cache_reset (ModelsCacheResetResponseCacheReset): Cache reset details + success (bool): Whether the operation succeeded + """ + + cache_reset: ModelsCacheResetResponseCacheReset + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + cache_reset = self.cache_reset.to_dict() + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "cache_reset": cache_reset, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_cache_reset_response_cache_reset import ModelsCacheResetResponseCacheReset + + d = dict(src_dict) + cache_reset = ModelsCacheResetResponseCacheReset.from_dict(d.pop("cache_reset")) + + success = d.pop("success") + + models_cache_reset_response = cls( + cache_reset=cache_reset, + success=success, + ) + + models_cache_reset_response.additional_properties = d + return models_cache_reset_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_cache_reset_response_cache_reset.py b/omni_python_sdk/models/models_cache_reset_response_cache_reset.py new file mode 100644 index 0000000..4a6da58 --- /dev/null +++ b/omni_python_sdk/models/models_cache_reset_response_cache_reset.py @@ -0,0 +1,113 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsCacheResetResponseCacheReset") + + +@_attrs_define +class ModelsCacheResetResponseCacheReset: + """Cache reset details + + Attributes: + created_at (None | str): Creation timestamp + model_id (str): Model ID + policy_name (str): Cache policy name + reset_at (None | str): Reset timestamp + updated_at (None | str): Last update timestamp + """ + + created_at: None | str + model_id: str + policy_name: str + reset_at: None | str + updated_at: None | str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created_at: None | str + created_at = self.created_at + + model_id = self.model_id + + policy_name = self.policy_name + + reset_at: None | str + reset_at = self.reset_at + + updated_at: None | str + updated_at = self.updated_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "created_at": created_at, + "model_id": model_id, + "policy_name": policy_name, + "reset_at": reset_at, + "updated_at": updated_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_created_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + created_at = _parse_created_at(d.pop("created_at")) + + model_id = d.pop("model_id") + + policy_name = d.pop("policy_name") + + def _parse_reset_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + reset_at = _parse_reset_at(d.pop("reset_at")) + + def _parse_updated_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + updated_at = _parse_updated_at(d.pop("updated_at")) + + models_cache_reset_response_cache_reset = cls( + created_at=created_at, + model_id=model_id, + policy_name=policy_name, + reset_at=reset_at, + updated_at=updated_at, + ) + + models_cache_reset_response_cache_reset.additional_properties = d + return models_cache_reset_response_cache_reset + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_commit_body.py b/omni_python_sdk/models/models_commit_body.py new file mode 100644 index 0000000..da1b8b6 --- /dev/null +++ b/omni_python_sdk/models/models_commit_body.py @@ -0,0 +1,94 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsCommitBody") + + +@_attrs_define +class ModelsCommitBody: + """ + Attributes: + branch_id (UUID): UUID of the branch to commit. Example: 123e4567-e89b-12d3-a456-426614174001. + commit_message (str): Commit message for the git commit. Example: Add new orders view. + allow_branch_exists (bool | Unset): If true (default), the commit succeeds whether the git branch already exists + or not. If false, the request fails when the git branch already exists — use this to ensure only new pull + requests are created. Cannot be false when require_branch_exists is true. Default: True. Example: True. + require_branch_exists (bool | Unset): If true, the request fails when the git branch does not already exist — + use this to ensure only existing pull requests are updated. Defaults to false. Cannot be true when + allow_branch_exists is false. Default: False. + """ + + branch_id: UUID + commit_message: str + allow_branch_exists: bool | Unset = True + require_branch_exists: bool | Unset = False + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + branch_id = str(self.branch_id) + + commit_message = self.commit_message + + allow_branch_exists = self.allow_branch_exists + + require_branch_exists = self.require_branch_exists + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "branch_id": branch_id, + "commit_message": commit_message, + } + ) + if allow_branch_exists is not UNSET: + field_dict["allow_branch_exists"] = allow_branch_exists + if require_branch_exists is not UNSET: + field_dict["require_branch_exists"] = require_branch_exists + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + branch_id = UUID(d.pop("branch_id")) + + commit_message = d.pop("commit_message") + + allow_branch_exists = d.pop("allow_branch_exists", UNSET) + + require_branch_exists = d.pop("require_branch_exists", UNSET) + + models_commit_body = cls( + branch_id=branch_id, + commit_message=commit_message, + allow_branch_exists=allow_branch_exists, + require_branch_exists=require_branch_exists, + ) + + models_commit_body.additional_properties = d + return models_commit_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_commit_response.py b/omni_python_sdk/models/models_commit_response.py new file mode 100644 index 0000000..cb0e684 --- /dev/null +++ b/omni_python_sdk/models/models_commit_response.py @@ -0,0 +1,98 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsCommitResponse") + + +@_attrs_define +class ModelsCommitResponse: + """ + Attributes: + did_sync (bool): Whether a sync operation was performed against git + git_sha (None | str): The git SHA of the commit that was pushed (null if no commit was needed) + in_sync (bool): Whether the branch is in sync with git after the operation + pr_url (None | str): The URL of the pull request (or PR creation page for newly-created PRs). May be null when + the underlying git provider is not recognized. + """ + + did_sync: bool + git_sha: None | str + in_sync: bool + pr_url: None | str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + did_sync = self.did_sync + + git_sha: None | str + git_sha = self.git_sha + + in_sync = self.in_sync + + pr_url: None | str + pr_url = self.pr_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "did_sync": did_sync, + "git_sha": git_sha, + "in_sync": in_sync, + "pr_url": pr_url, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + did_sync = d.pop("did_sync") + + def _parse_git_sha(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + git_sha = _parse_git_sha(d.pop("git_sha")) + + in_sync = d.pop("in_sync") + + def _parse_pr_url(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + pr_url = _parse_pr_url(d.pop("pr_url")) + + models_commit_response = cls( + did_sync=did_sync, + git_sha=git_sha, + in_sync=in_sync, + pr_url=pr_url, + ) + + models_commit_response.additional_properties = d + return models_commit_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_content_validator_get_find_type.py b/omni_python_sdk/models/models_content_validator_get_find_type.py new file mode 100644 index 0000000..71ffb9e --- /dev/null +++ b/omni_python_sdk/models/models_content_validator_get_find_type.py @@ -0,0 +1,15 @@ +from typing import Literal + +ModelsContentValidatorGetFindType = Literal["FIELD", "TOPIC", "VIEW"] + +MODELS_CONTENT_VALIDATOR_GET_FIND_TYPE_VALUES: set[ModelsContentValidatorGetFindType] = { + "FIELD", + "TOPIC", + "VIEW", +} + + +def check_models_content_validator_get_find_type(value: str) -> ModelsContentValidatorGetFindType: + if value in MODELS_CONTENT_VALIDATOR_GET_FIND_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_CONTENT_VALIDATOR_GET_FIND_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/models_content_validator_get_response.py b/omni_python_sdk/models/models_content_validator_get_response.py new file mode 100644 index 0000000..81a7b0b --- /dev/null +++ b/omni_python_sdk/models/models_content_validator_get_response.py @@ -0,0 +1,109 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.models_content_validator_get_response_branch_type_0 import ( + ModelsContentValidatorGetResponseBranchType0, + ) + + +T = TypeVar("T", bound="ModelsContentValidatorGetResponse") + + +@_attrs_define +class ModelsContentValidatorGetResponse: + """ + Attributes: + branch (ModelsContentValidatorGetResponseBranchType0 | None): Branch info (present if branch_id was specified) + content (list[Any]): Documents with their validation results + model_id (str): Model UUID + """ + + branch: ModelsContentValidatorGetResponseBranchType0 | None + content: list[Any] + model_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.models_content_validator_get_response_branch_type_0 import ( + ModelsContentValidatorGetResponseBranchType0, + ) + + branch: dict[str, Any] | None + if isinstance(self.branch, ModelsContentValidatorGetResponseBranchType0): + branch = self.branch.to_dict() + else: + branch = self.branch + + content = self.content + + model_id = self.model_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "branch": branch, + "content": content, + "model_id": model_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_content_validator_get_response_branch_type_0 import ( + ModelsContentValidatorGetResponseBranchType0, + ) + + d = dict(src_dict) + + def _parse_branch(data: object) -> ModelsContentValidatorGetResponseBranchType0 | None: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + branch_type_0 = ModelsContentValidatorGetResponseBranchType0.from_dict(data) + + return branch_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(ModelsContentValidatorGetResponseBranchType0 | None, data) + + branch = _parse_branch(d.pop("branch")) + + content = cast(list[Any], d.pop("content")) + + model_id = d.pop("model_id") + + models_content_validator_get_response = cls( + branch=branch, + content=content, + model_id=model_id, + ) + + models_content_validator_get_response.additional_properties = d + return models_content_validator_get_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_content_validator_get_response_branch_type_0.py b/omni_python_sdk/models/models_content_validator_get_response_branch_type_0.py new file mode 100644 index 0000000..e9d3ee8 --- /dev/null +++ b/omni_python_sdk/models/models_content_validator_get_response_branch_type_0.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsContentValidatorGetResponseBranchType0") + + +@_attrs_define +class ModelsContentValidatorGetResponseBranchType0: + """Branch info (present if branch_id was specified) + + Attributes: + id (str): Branch UUID + name (str): Branch name + """ + + id: str + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + name = d.pop("name") + + models_content_validator_get_response_branch_type_0 = cls( + id=id, + name=name, + ) + + models_content_validator_get_response_branch_type_0.additional_properties = d + return models_content_validator_get_response_branch_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_content_validator_replace_body.py b/omni_python_sdk/models/models_content_validator_replace_body.py new file mode 100644 index 0000000..3ec9659 --- /dev/null +++ b/omni_python_sdk/models/models_content_validator_replace_body.py @@ -0,0 +1,151 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.models_content_validator_replace_body_find_or_replace_type import ( + ModelsContentValidatorReplaceBodyFindOrReplaceType, + check_models_content_validator_replace_body_find_or_replace_type, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsContentValidatorReplaceBody") + + +@_attrs_define +class ModelsContentValidatorReplaceBody: + """ + Attributes: + find (str): The string to find + find_or_replace_type (ModelsContentValidatorReplaceBodyFindOrReplaceType): Type of find/replace operation. + replacement (str): The replacement string + branch_id (str | Unset): Optional branch ID + creator_id (UUID | Unset): Restrict replacement to documents created by this user (user ID). Unknown IDs return + 400. + folder_paths (list[str] | Unset): Restrict replacement to documents in matching folder paths (prefix match). + Documents with no folder are excluded unless "" is specified. + include_personal_folders (bool | Unset): Whether to include personal folders Default: False. + labels (str | Unset): Comma-separated label names to scope replacement. Unknown labels return 400. + only_in_workbook_id (str | Unset): Optional workbook ID to limit the replace scope + """ + + find: str + find_or_replace_type: ModelsContentValidatorReplaceBodyFindOrReplaceType + replacement: str + branch_id: str | Unset = UNSET + creator_id: UUID | Unset = UNSET + folder_paths: list[str] | Unset = UNSET + include_personal_folders: bool | Unset = False + labels: str | Unset = UNSET + only_in_workbook_id: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + find = self.find + + find_or_replace_type: str = self.find_or_replace_type + + replacement = self.replacement + + branch_id = self.branch_id + + creator_id: str | Unset = UNSET + if not isinstance(self.creator_id, Unset): + creator_id = str(self.creator_id) + + folder_paths: list[str] | Unset = UNSET + if not isinstance(self.folder_paths, Unset): + folder_paths = self.folder_paths + + include_personal_folders = self.include_personal_folders + + labels = self.labels + + only_in_workbook_id = self.only_in_workbook_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "find": find, + "find_or_replace_type": find_or_replace_type, + "replacement": replacement, + } + ) + if branch_id is not UNSET: + field_dict["branch_id"] = branch_id + if creator_id is not UNSET: + field_dict["creator_id"] = creator_id + if folder_paths is not UNSET: + field_dict["folder_paths"] = folder_paths + if include_personal_folders is not UNSET: + field_dict["include_personal_folders"] = include_personal_folders + if labels is not UNSET: + field_dict["labels"] = labels + if only_in_workbook_id is not UNSET: + field_dict["only_in_workbook_id"] = only_in_workbook_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + find = d.pop("find") + + find_or_replace_type = check_models_content_validator_replace_body_find_or_replace_type( + d.pop("find_or_replace_type") + ) + + replacement = d.pop("replacement") + + branch_id = d.pop("branch_id", UNSET) + + _creator_id = d.pop("creator_id", UNSET) + creator_id: UUID | Unset + if isinstance(_creator_id, Unset): + creator_id = UNSET + else: + creator_id = UUID(_creator_id) + + folder_paths = cast(list[str], d.pop("folder_paths", UNSET)) + + include_personal_folders = d.pop("include_personal_folders", UNSET) + + labels = d.pop("labels", UNSET) + + only_in_workbook_id = d.pop("only_in_workbook_id", UNSET) + + models_content_validator_replace_body = cls( + find=find, + find_or_replace_type=find_or_replace_type, + replacement=replacement, + branch_id=branch_id, + creator_id=creator_id, + folder_paths=folder_paths, + include_personal_folders=include_personal_folders, + labels=labels, + only_in_workbook_id=only_in_workbook_id, + ) + + models_content_validator_replace_body.additional_properties = d + return models_content_validator_replace_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_content_validator_replace_body_find_or_replace_type.py b/omni_python_sdk/models/models_content_validator_replace_body_find_or_replace_type.py new file mode 100644 index 0000000..5d59b1b --- /dev/null +++ b/omni_python_sdk/models/models_content_validator_replace_body_find_or_replace_type.py @@ -0,0 +1,21 @@ +from typing import Literal + +ModelsContentValidatorReplaceBodyFindOrReplaceType = Literal["FIELD", "TOPIC", "VIEW"] + +MODELS_CONTENT_VALIDATOR_REPLACE_BODY_FIND_OR_REPLACE_TYPE_VALUES: set[ + ModelsContentValidatorReplaceBodyFindOrReplaceType +] = { + "FIELD", + "TOPIC", + "VIEW", +} + + +def check_models_content_validator_replace_body_find_or_replace_type( + value: str, +) -> ModelsContentValidatorReplaceBodyFindOrReplaceType: + if value in MODELS_CONTENT_VALIDATOR_REPLACE_BODY_FIND_OR_REPLACE_TYPE_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {MODELS_CONTENT_VALIDATOR_REPLACE_BODY_FIND_OR_REPLACE_TYPE_VALUES!r}" + ) diff --git a/omni_python_sdk/models/models_content_validator_replace_response.py b/omni_python_sdk/models/models_content_validator_replace_response.py new file mode 100644 index 0000000..06d6f71 --- /dev/null +++ b/omni_python_sdk/models/models_content_validator_replace_response.py @@ -0,0 +1,101 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsContentValidatorReplaceResponse") + + +@_attrs_define +class ModelsContentValidatorReplaceResponse: + """ + Attributes: + replaced_dashboard_filters_count (int): Number of dashboard filters replaced + replaced_documents_count (int): Number of documents modified + replaced_input_column_keys_count (int): Number of input columns whose key references were replaced + replaced_queries_count (int): Number of queries replaced + replaced_workbook_models_count (int): Number of workbook models replaced + skipped_pr_required_count (int): Number of documents skipped due to pull request requirements + """ + + replaced_dashboard_filters_count: int + replaced_documents_count: int + replaced_input_column_keys_count: int + replaced_queries_count: int + replaced_workbook_models_count: int + skipped_pr_required_count: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + replaced_dashboard_filters_count = self.replaced_dashboard_filters_count + + replaced_documents_count = self.replaced_documents_count + + replaced_input_column_keys_count = self.replaced_input_column_keys_count + + replaced_queries_count = self.replaced_queries_count + + replaced_workbook_models_count = self.replaced_workbook_models_count + + skipped_pr_required_count = self.skipped_pr_required_count + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "replaced_dashboard_filters_count": replaced_dashboard_filters_count, + "replaced_documents_count": replaced_documents_count, + "replaced_input_column_keys_count": replaced_input_column_keys_count, + "replaced_queries_count": replaced_queries_count, + "replaced_workbook_models_count": replaced_workbook_models_count, + "skipped_pr_required_count": skipped_pr_required_count, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + replaced_dashboard_filters_count = d.pop("replaced_dashboard_filters_count") + + replaced_documents_count = d.pop("replaced_documents_count") + + replaced_input_column_keys_count = d.pop("replaced_input_column_keys_count") + + replaced_queries_count = d.pop("replaced_queries_count") + + replaced_workbook_models_count = d.pop("replaced_workbook_models_count") + + skipped_pr_required_count = d.pop("skipped_pr_required_count") + + models_content_validator_replace_response = cls( + replaced_dashboard_filters_count=replaced_dashboard_filters_count, + replaced_documents_count=replaced_documents_count, + replaced_input_column_keys_count=replaced_input_column_keys_count, + replaced_queries_count=replaced_queries_count, + replaced_workbook_models_count=replaced_workbook_models_count, + skipped_pr_required_count=skipped_pr_required_count, + ) + + models_content_validator_replace_response.additional_properties = d + return models_content_validator_replace_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_create_field_body.py b/omni_python_sdk/models/models_create_field_body.py new file mode 100644 index 0000000..1e5b591 --- /dev/null +++ b/omni_python_sdk/models/models_create_field_body.py @@ -0,0 +1,148 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define + +from ..models.models_create_field_body_aggregate_type import ( + ModelsCreateFieldBodyAggregateType, + check_models_create_field_body_aggregate_type, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsCreateFieldBody") + + +@_attrs_define +class ModelsCreateFieldBody: + """ + Attributes: + field_name (str): Field name Example: total_revenue. + view_name (str): View to add the field to Example: orders. + aggregate_type (ModelsCreateFieldBodyAggregateType | Unset): Aggregate type for measures. Setting this property + promotes the field to a measure (written under `measures:`); omit it to create a dimension (written under + `dimensions:`). Values must be uppercase canonical names. Example: SUM. + ai_context (str | Unset): AI context for the field + description (str | Unset): Field description + format_ (str | Unset): Field format + hidden (bool | Unset): Whether the field is hidden + label (str | Unset): Field label + sql (str | Unset): SQL expression for the field + tags (list[str] | Unset): Tags for the field + topic_context (str | Unset): Topic context for topic-scoped fields + """ + + field_name: str + view_name: str + aggregate_type: ModelsCreateFieldBodyAggregateType | Unset = UNSET + ai_context: str | Unset = UNSET + description: str | Unset = UNSET + format_: str | Unset = UNSET + hidden: bool | Unset = UNSET + label: str | Unset = UNSET + sql: str | Unset = UNSET + tags: list[str] | Unset = UNSET + topic_context: str | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + field_name = self.field_name + + view_name = self.view_name + + aggregate_type: str | Unset = UNSET + if not isinstance(self.aggregate_type, Unset): + aggregate_type = self.aggregate_type + + ai_context = self.ai_context + + description = self.description + + format_ = self.format_ + + hidden = self.hidden + + label = self.label + + sql = self.sql + + tags: list[str] | Unset = UNSET + if not isinstance(self.tags, Unset): + tags = self.tags + + topic_context = self.topic_context + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "fieldName": field_name, + "viewName": view_name, + } + ) + if aggregate_type is not UNSET: + field_dict["aggregateType"] = aggregate_type + if ai_context is not UNSET: + field_dict["aiContext"] = ai_context + if description is not UNSET: + field_dict["description"] = description + if format_ is not UNSET: + field_dict["format"] = format_ + if hidden is not UNSET: + field_dict["hidden"] = hidden + if label is not UNSET: + field_dict["label"] = label + if sql is not UNSET: + field_dict["sql"] = sql + if tags is not UNSET: + field_dict["tags"] = tags + if topic_context is not UNSET: + field_dict["topicContext"] = topic_context + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + field_name = d.pop("fieldName") + + view_name = d.pop("viewName") + + _aggregate_type = d.pop("aggregateType", UNSET) + aggregate_type: ModelsCreateFieldBodyAggregateType | Unset + if isinstance(_aggregate_type, Unset): + aggregate_type = UNSET + else: + aggregate_type = check_models_create_field_body_aggregate_type(_aggregate_type) + + ai_context = d.pop("aiContext", UNSET) + + description = d.pop("description", UNSET) + + format_ = d.pop("format", UNSET) + + hidden = d.pop("hidden", UNSET) + + label = d.pop("label", UNSET) + + sql = d.pop("sql", UNSET) + + tags = cast(list[str], d.pop("tags", UNSET)) + + topic_context = d.pop("topicContext", UNSET) + + models_create_field_body = cls( + field_name=field_name, + view_name=view_name, + aggregate_type=aggregate_type, + ai_context=ai_context, + description=description, + format_=format_, + hidden=hidden, + label=label, + sql=sql, + tags=tags, + topic_context=topic_context, + ) + + return models_create_field_body diff --git a/omni_python_sdk/models/models_create_field_body_aggregate_type.py b/omni_python_sdk/models/models_create_field_body_aggregate_type.py new file mode 100644 index 0000000..24cdc8b --- /dev/null +++ b/omni_python_sdk/models/models_create_field_body_aggregate_type.py @@ -0,0 +1,41 @@ +from typing import Literal + +ModelsCreateFieldBodyAggregateType = Literal[ + "AVERAGE", + "AVERAGE_DISTINCT_ON", + "COUNT", + "COUNT_DISTINCT", + "LIST", + "MAX", + "MEDIAN", + "MEDIAN_DISTINCT_ON", + "MIN", + "PERCENTILE", + "PERCENTILE_DISTINCT_ON", + "SEMANTIC_VIEW_AGG", + "SUM", + "SUM_DISTINCT_ON", +] + +MODELS_CREATE_FIELD_BODY_AGGREGATE_TYPE_VALUES: set[ModelsCreateFieldBodyAggregateType] = { + "AVERAGE", + "AVERAGE_DISTINCT_ON", + "COUNT", + "COUNT_DISTINCT", + "LIST", + "MAX", + "MEDIAN", + "MEDIAN_DISTINCT_ON", + "MIN", + "PERCENTILE", + "PERCENTILE_DISTINCT_ON", + "SEMANTIC_VIEW_AGG", + "SUM", + "SUM_DISTINCT_ON", +} + + +def check_models_create_field_body_aggregate_type(value: str) -> ModelsCreateFieldBodyAggregateType: + if value in MODELS_CREATE_FIELD_BODY_AGGREGATE_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_CREATE_FIELD_BODY_AGGREGATE_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/models_create_models_create_response.py b/omni_python_sdk/models/models_create_models_create_response.py new file mode 100644 index 0000000..b252d46 --- /dev/null +++ b/omni_python_sdk/models/models_create_models_create_response.py @@ -0,0 +1,104 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.models_create_models_create_response_model import ModelsCreateModelsCreateResponseModel + + +T = TypeVar("T", bound="ModelsCreateModelsCreateResponse") + + +@_attrs_define +class ModelsCreateModelsCreateResponse: + """Create model response + + Attributes: + success (bool): Whether the operation succeeded + error (str | Unset): Error message if creation failed + message (str | Unset): Additional message + model (ModelsCreateModelsCreateResponseModel | Unset): Created model details + """ + + success: bool + error: str | Unset = UNSET + message: str | Unset = UNSET + model: ModelsCreateModelsCreateResponseModel | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + error = self.error + + message = self.message + + model: dict[str, Any] | Unset = UNSET + if not isinstance(self.model, Unset): + model = self.model.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + } + ) + if error is not UNSET: + field_dict["error"] = error + if message is not UNSET: + field_dict["message"] = message + if model is not UNSET: + field_dict["model"] = model + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_create_models_create_response_model import ModelsCreateModelsCreateResponseModel + + d = dict(src_dict) + success = d.pop("success") + + error = d.pop("error", UNSET) + + message = d.pop("message", UNSET) + + _model = d.pop("model", UNSET) + model: ModelsCreateModelsCreateResponseModel | Unset + if isinstance(_model, Unset): + model = UNSET + else: + model = ModelsCreateModelsCreateResponseModel.from_dict(_model) + + models_create_models_create_response = cls( + success=success, + error=error, + message=message, + model=model, + ) + + models_create_models_create_response.additional_properties = d + return models_create_models_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_create_models_create_response_model.py b/omni_python_sdk/models/models_create_models_create_response_model.py new file mode 100644 index 0000000..369c808 --- /dev/null +++ b/omni_python_sdk/models/models_create_models_create_response_model.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsCreateModelsCreateResponseModel") + + +@_attrs_define +class ModelsCreateModelsCreateResponseModel: + """Created model details + + Attributes: + id (UUID): Created model ID + model_kind (str): Kind of model created + name (None | str): Model name + """ + + id: UUID + model_kind: str + name: None | str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + model_kind = self.model_kind + + name: None | str + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "modelKind": model_kind, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = UUID(d.pop("id")) + + model_kind = d.pop("modelKind") + + def _parse_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + name = _parse_name(d.pop("name")) + + models_create_models_create_response_model = cls( + id=id, + model_kind=model_kind, + name=name, + ) + + models_create_models_create_response_model.additional_properties = d + return models_create_models_create_response_model + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_dbt_exposures_response.py b/omni_python_sdk/models/models_dbt_exposures_response.py new file mode 100644 index 0000000..99fc2e9 --- /dev/null +++ b/omni_python_sdk/models/models_dbt_exposures_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.dbt_exposure_with_meta import DbtExposureWithMeta + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="ModelsDbtExposuresResponse") + + +@_attrs_define +class ModelsDbtExposuresResponse: + """ + Attributes: + page_info (PageInfo): + records (list[DbtExposureWithMeta]): + """ + + page_info: PageInfo + records: list[DbtExposureWithMeta] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.dbt_exposure_with_meta import DbtExposureWithMeta + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = DbtExposureWithMeta.from_dict(records_item_data) + + records.append(records_item) + + models_dbt_exposures_response = cls( + page_info=page_info, + records=records, + ) + + models_dbt_exposures_response.additional_properties = d + return models_dbt_exposures_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_dbt_exposures_sort_direction.py b/omni_python_sdk/models/models_dbt_exposures_sort_direction.py new file mode 100644 index 0000000..4575193 --- /dev/null +++ b/omni_python_sdk/models/models_dbt_exposures_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +ModelsDbtExposuresSortDirection = Literal["asc", "desc"] + +MODELS_DBT_EXPOSURES_SORT_DIRECTION_VALUES: set[ModelsDbtExposuresSortDirection] = { + "asc", + "desc", +} + + +def check_models_dbt_exposures_sort_direction(value: str) -> ModelsDbtExposuresSortDirection: + if value in MODELS_DBT_EXPOSURES_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_DBT_EXPOSURES_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/models_delete_topic_mode.py b/omni_python_sdk/models/models_delete_topic_mode.py new file mode 100644 index 0000000..f7d5a87 --- /dev/null +++ b/omni_python_sdk/models/models_delete_topic_mode.py @@ -0,0 +1,15 @@ +from typing import Literal + +ModelsDeleteTopicMode = Literal["COMBINED", "EXTENSION", "MERGED"] + +MODELS_DELETE_TOPIC_MODE_VALUES: set[ModelsDeleteTopicMode] = { + "COMBINED", + "EXTENSION", + "MERGED", +} + + +def check_models_delete_topic_mode(value: str) -> ModelsDeleteTopicMode: + if value in MODELS_DELETE_TOPIC_MODE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_DELETE_TOPIC_MODE_VALUES!r}") diff --git a/omni_python_sdk/models/models_delete_view_mode.py b/omni_python_sdk/models/models_delete_view_mode.py new file mode 100644 index 0000000..be9b07d --- /dev/null +++ b/omni_python_sdk/models/models_delete_view_mode.py @@ -0,0 +1,15 @@ +from typing import Literal + +ModelsDeleteViewMode = Literal["COMBINED", "EXTENSION", "MERGED"] + +MODELS_DELETE_VIEW_MODE_VALUES: set[ModelsDeleteViewMode] = { + "COMBINED", + "EXTENSION", + "MERGED", +} + + +def check_models_delete_view_mode(value: str) -> ModelsDeleteViewMode: + if value in MODELS_DELETE_VIEW_MODE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_DELETE_VIEW_MODE_VALUES!r}") diff --git a/omni_python_sdk/models/models_get_schemas_response.py b/omni_python_sdk/models/models_get_schemas_response.py new file mode 100644 index 0000000..05605b6 --- /dev/null +++ b/omni_python_sdk/models/models_get_schemas_response.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsGetSchemasResponse") + + +@_attrs_define +class ModelsGetSchemasResponse: + """ + Attributes: + schemas (list[str]): Sorted list of all available schema names (catalog-scoped if applicable, e.g. + warehouse.reporting) + """ + + schemas: list[str] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + schemas = self.schemas + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "schemas": schemas, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + schemas = cast(list[str], d.pop("schemas")) + + models_get_schemas_response = cls( + schemas=schemas, + ) + + models_get_schemas_response.additional_properties = d + return models_get_schemas_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_get_topic_response.py b/omni_python_sdk/models/models_get_topic_response.py new file mode 100644 index 0000000..b9768cd --- /dev/null +++ b/omni_python_sdk/models/models_get_topic_response.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.models_get_topic_response_topic import ModelsGetTopicResponseTopic + + +T = TypeVar("T", bound="ModelsGetTopicResponse") + + +@_attrs_define +class ModelsGetTopicResponse: + """ + Attributes: + success (bool): Whether the operation succeeded + topic (ModelsGetTopicResponseTopic): Topic details with relationships and views + """ + + success: bool + topic: ModelsGetTopicResponseTopic + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + topic = self.topic.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + "topic": topic, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_get_topic_response_topic import ModelsGetTopicResponseTopic + + d = dict(src_dict) + success = d.pop("success") + + topic = ModelsGetTopicResponseTopic.from_dict(d.pop("topic")) + + models_get_topic_response = cls( + success=success, + topic=topic, + ) + + models_get_topic_response.additional_properties = d + return models_get_topic_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_get_topic_response_topic.py b/omni_python_sdk/models/models_get_topic_response_topic.py new file mode 100644 index 0000000..768661b --- /dev/null +++ b/omni_python_sdk/models/models_get_topic_response_topic.py @@ -0,0 +1,150 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.models_get_topic_response_topic_relationships_item import ModelsGetTopicResponseTopicRelationshipsItem + from ..models.models_get_topic_response_topic_views_item import ModelsGetTopicResponseTopicViewsItem + + +T = TypeVar("T", bound="ModelsGetTopicResponseTopic") + + +@_attrs_define +class ModelsGetTopicResponseTopic: + """Topic details with relationships and views + + Attributes: + base_view_name (str): Base view name for the topic + name (str): Topic name + relationships (list[ModelsGetTopicResponseTopicRelationshipsItem]): Relationships for the topic + views (list[ModelsGetTopicResponseTopicViewsItem]): Views available in the topic + description (str | Unset): Topic description + group_label (str | Unset): Group label + hidden (bool | Unset): Whether the topic is hidden + label (str | Unset): Topic label + """ + + base_view_name: str + name: str + relationships: list[ModelsGetTopicResponseTopicRelationshipsItem] + views: list[ModelsGetTopicResponseTopicViewsItem] + description: str | Unset = UNSET + group_label: str | Unset = UNSET + hidden: bool | Unset = UNSET + label: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + base_view_name = self.base_view_name + + name = self.name + + relationships = [] + for relationships_item_data in self.relationships: + relationships_item = relationships_item_data.to_dict() + relationships.append(relationships_item) + + views = [] + for views_item_data in self.views: + views_item = views_item_data.to_dict() + views.append(views_item) + + description = self.description + + group_label = self.group_label + + hidden = self.hidden + + label = self.label + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "base_view_name": base_view_name, + "name": name, + "relationships": relationships, + "views": views, + } + ) + if description is not UNSET: + field_dict["description"] = description + if group_label is not UNSET: + field_dict["group_label"] = group_label + if hidden is not UNSET: + field_dict["hidden"] = hidden + if label is not UNSET: + field_dict["label"] = label + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_get_topic_response_topic_relationships_item import ( + ModelsGetTopicResponseTopicRelationshipsItem, + ) + from ..models.models_get_topic_response_topic_views_item import ModelsGetTopicResponseTopicViewsItem + + d = dict(src_dict) + base_view_name = d.pop("base_view_name") + + name = d.pop("name") + + relationships = [] + _relationships = d.pop("relationships") + for relationships_item_data in _relationships: + relationships_item = ModelsGetTopicResponseTopicRelationshipsItem.from_dict(relationships_item_data) + + relationships.append(relationships_item) + + views = [] + _views = d.pop("views") + for views_item_data in _views: + views_item = ModelsGetTopicResponseTopicViewsItem.from_dict(views_item_data) + + views.append(views_item) + + description = d.pop("description", UNSET) + + group_label = d.pop("group_label", UNSET) + + hidden = d.pop("hidden", UNSET) + + label = d.pop("label", UNSET) + + models_get_topic_response_topic = cls( + base_view_name=base_view_name, + name=name, + relationships=relationships, + views=views, + description=description, + group_label=group_label, + hidden=hidden, + label=label, + ) + + models_get_topic_response_topic.additional_properties = d + return models_get_topic_response_topic + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_get_topic_response_topic_relationships_item.py b/omni_python_sdk/models/models_get_topic_response_topic_relationships_item.py new file mode 100644 index 0000000..55c1d2c --- /dev/null +++ b/omni_python_sdk/models/models_get_topic_response_topic_relationships_item.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsGetTopicResponseTopicRelationshipsItem") + + +@_attrs_define +class ModelsGetTopicResponseTopicRelationshipsItem: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + models_get_topic_response_topic_relationships_item = cls() + + models_get_topic_response_topic_relationships_item.additional_properties = d + return models_get_topic_response_topic_relationships_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_get_topic_response_topic_views_item.py b/omni_python_sdk/models/models_get_topic_response_topic_views_item.py new file mode 100644 index 0000000..5b10958 --- /dev/null +++ b/omni_python_sdk/models/models_get_topic_response_topic_views_item.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsGetTopicResponseTopicViewsItem") + + +@_attrs_define +class ModelsGetTopicResponseTopicViewsItem: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + models_get_topic_response_topic_views_item = cls() + + models_get_topic_response_topic_views_item.additional_properties = d + return models_get_topic_response_topic_views_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_get_view_response.py b/omni_python_sdk/models/models_get_view_response.py new file mode 100644 index 0000000..d953895 --- /dev/null +++ b/omni_python_sdk/models/models_get_view_response.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.models_get_view_response_views_item import ModelsGetViewResponseViewsItem + + +T = TypeVar("T", bound="ModelsGetViewResponse") + + +@_attrs_define +class ModelsGetViewResponse: + """ + Attributes: + success (bool): Whether the operation succeeded + views (list[ModelsGetViewResponseViewsItem]): List of views + """ + + success: bool + views: list[ModelsGetViewResponseViewsItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + views = [] + for views_item_data in self.views: + views_item = views_item_data.to_dict() + views.append(views_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + "views": views, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_get_view_response_views_item import ModelsGetViewResponseViewsItem + + d = dict(src_dict) + success = d.pop("success") + + views = [] + _views = d.pop("views") + for views_item_data in _views: + views_item = ModelsGetViewResponseViewsItem.from_dict(views_item_data) + + views.append(views_item) + + models_get_view_response = cls( + success=success, + views=views, + ) + + models_get_view_response.additional_properties = d + return models_get_view_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_get_view_response_views_item.py b/omni_python_sdk/models/models_get_view_response_views_item.py new file mode 100644 index 0000000..a3460fb --- /dev/null +++ b/omni_python_sdk/models/models_get_view_response_views_item.py @@ -0,0 +1,112 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.models_get_view_response_views_item_fields_item import ModelsGetViewResponseViewsItemFieldsItem + + +T = TypeVar("T", bound="ModelsGetViewResponseViewsItem") + + +@_attrs_define +class ModelsGetViewResponseViewsItem: + """ + Attributes: + fields (list[ModelsGetViewResponseViewsItemFieldsItem]): Fields in the view + name (str): View name + description (str | Unset): View description + hidden (bool | Unset): Whether the view is hidden + label (str | Unset): View label + """ + + fields: list[ModelsGetViewResponseViewsItemFieldsItem] + name: str + description: str | Unset = UNSET + hidden: bool | Unset = UNSET + label: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + fields = [] + for fields_item_data in self.fields: + fields_item = fields_item_data.to_dict() + fields.append(fields_item) + + name = self.name + + description = self.description + + hidden = self.hidden + + label = self.label + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "fields": fields, + "name": name, + } + ) + if description is not UNSET: + field_dict["description"] = description + if hidden is not UNSET: + field_dict["hidden"] = hidden + if label is not UNSET: + field_dict["label"] = label + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_get_view_response_views_item_fields_item import ModelsGetViewResponseViewsItemFieldsItem + + d = dict(src_dict) + fields = [] + _fields = d.pop("fields") + for fields_item_data in _fields: + fields_item = ModelsGetViewResponseViewsItemFieldsItem.from_dict(fields_item_data) + + fields.append(fields_item) + + name = d.pop("name") + + description = d.pop("description", UNSET) + + hidden = d.pop("hidden", UNSET) + + label = d.pop("label", UNSET) + + models_get_view_response_views_item = cls( + fields=fields, + name=name, + description=description, + hidden=hidden, + label=label, + ) + + models_get_view_response_views_item.additional_properties = d + return models_get_view_response_views_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_get_view_response_views_item_fields_item.py b/omni_python_sdk/models/models_get_view_response_views_item_fields_item.py new file mode 100644 index 0000000..21927da --- /dev/null +++ b/omni_python_sdk/models/models_get_view_response_views_item_fields_item.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.models_get_view_response_views_item_fields_item_type import ( + ModelsGetViewResponseViewsItemFieldsItemType, + check_models_get_view_response_views_item_fields_item_type, +) + +T = TypeVar("T", bound="ModelsGetViewResponseViewsItemFieldsItem") + + +@_attrs_define +class ModelsGetViewResponseViewsItemFieldsItem: + """ + Attributes: + name (str): Field name + type_ (ModelsGetViewResponseViewsItemFieldsItemType): Field type + """ + + name: str + type_: ModelsGetViewResponseViewsItemFieldsItemType + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + type_: str = self.type_ + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "type": type_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + name = d.pop("name") + + type_ = check_models_get_view_response_views_item_fields_item_type(d.pop("type")) + + models_get_view_response_views_item_fields_item = cls( + name=name, + type_=type_, + ) + + models_get_view_response_views_item_fields_item.additional_properties = d + return models_get_view_response_views_item_fields_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_get_view_response_views_item_fields_item_type.py b/omni_python_sdk/models/models_get_view_response_views_item_fields_item_type.py new file mode 100644 index 0000000..4aa372b --- /dev/null +++ b/omni_python_sdk/models/models_get_view_response_views_item_fields_item_type.py @@ -0,0 +1,19 @@ +from typing import Literal + +ModelsGetViewResponseViewsItemFieldsItemType = Literal["dimension", "filter", "measure"] + +MODELS_GET_VIEW_RESPONSE_VIEWS_ITEM_FIELDS_ITEM_TYPE_VALUES: set[ModelsGetViewResponseViewsItemFieldsItemType] = { + "dimension", + "filter", + "measure", +} + + +def check_models_get_view_response_views_item_fields_item_type( + value: str, +) -> ModelsGetViewResponseViewsItemFieldsItemType: + if value in MODELS_GET_VIEW_RESPONSE_VIEWS_ITEM_FIELDS_ITEM_TYPE_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {MODELS_GET_VIEW_RESPONSE_VIEWS_ITEM_FIELDS_ITEM_TYPE_VALUES!r}" + ) diff --git a/omni_python_sdk/models/models_git_create_body.py b/omni_python_sdk/models/models_git_create_body.py new file mode 100644 index 0000000..8fead04 --- /dev/null +++ b/omni_python_sdk/models/models_git_create_body.py @@ -0,0 +1,195 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.models_git_create_body_auth_method import ( + ModelsGitCreateBodyAuthMethod, + check_models_git_create_body_auth_method, +) +from ..models.models_git_create_body_git_service_provider import ( + ModelsGitCreateBodyGitServiceProvider, + check_models_git_create_body_git_service_provider, +) +from ..models.models_git_create_body_require_pull_request import ( + ModelsGitCreateBodyRequirePullRequest, + check_models_git_create_body_require_pull_request, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsGitCreateBody") + + +@_attrs_define +class ModelsGitCreateBody: + """ + Attributes: + auth_method (ModelsGitCreateBodyAuthMethod | Unset): Authentication method. "ssh" for deploy key (default), + "https_token" for deploy token/PAT. Default: 'ssh'. Example: ssh. + base_branch (str | Unset): The target branch for Omni pull requests. Defaults to "main" Default: 'main'. + Example: main. + branch_per_pull_request (bool | Unset): If true, all pull requests will create a branch in Omni. Defaults to + false Default: False. + clone_url (str | Unset): Clone URL of the git repository. SSH (git@...) for deploy key auth, HTTPS (https://...) + for token auth. Example: git@github.com:org/repo.git. + git_follower (bool | Unset): If true, the shared model will be read-only. Defaults to false Default: False. + git_service_provider (ModelsGitCreateBodyGitServiceProvider | Unset): The git provider type. Use "auto" for + automatic detection. Defaults to "auto" Default: 'auto'. Example: auto. + model_path (str | Unset): Path to model files in the repository. Defaults to omni/. Use a plain name + (e.g., "my_model") for omni/my_model, or a leading slash for a custom path (e.g., "/bi/models/sales") Example: + my_model. + require_pull_request (ModelsGitCreateBodyRequirePullRequest | Unset): Controls when pull requests are required. + Defaults to "never" Default: 'never'. Example: never. + ssh_url (str | Unset): Deprecated — use cloneUrl. Clone URL of the git repository. Example: + git@github.com:org/repo.git. + token (str | Unset): HTTPS token for authentication (deploy token value, PAT, etc.). Required when authMethod is + "https_token". + web_url (str | Unset): Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC + and differs from the inferred HTTPS address Example: https://github.com/org/repo. + """ + + auth_method: ModelsGitCreateBodyAuthMethod | Unset = "ssh" + base_branch: str | Unset = "main" + branch_per_pull_request: bool | Unset = False + clone_url: str | Unset = UNSET + git_follower: bool | Unset = False + git_service_provider: ModelsGitCreateBodyGitServiceProvider | Unset = "auto" + model_path: str | Unset = UNSET + require_pull_request: ModelsGitCreateBodyRequirePullRequest | Unset = "never" + ssh_url: str | Unset = UNSET + token: str | Unset = UNSET + web_url: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + auth_method: str | Unset = UNSET + if not isinstance(self.auth_method, Unset): + auth_method = self.auth_method + + base_branch = self.base_branch + + branch_per_pull_request = self.branch_per_pull_request + + clone_url = self.clone_url + + git_follower = self.git_follower + + git_service_provider: str | Unset = UNSET + if not isinstance(self.git_service_provider, Unset): + git_service_provider = self.git_service_provider + + model_path = self.model_path + + require_pull_request: str | Unset = UNSET + if not isinstance(self.require_pull_request, Unset): + require_pull_request = self.require_pull_request + + ssh_url = self.ssh_url + + token = self.token + + web_url = self.web_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if auth_method is not UNSET: + field_dict["authMethod"] = auth_method + if base_branch is not UNSET: + field_dict["baseBranch"] = base_branch + if branch_per_pull_request is not UNSET: + field_dict["branchPerPullRequest"] = branch_per_pull_request + if clone_url is not UNSET: + field_dict["cloneUrl"] = clone_url + if git_follower is not UNSET: + field_dict["gitFollower"] = git_follower + if git_service_provider is not UNSET: + field_dict["gitServiceProvider"] = git_service_provider + if model_path is not UNSET: + field_dict["modelPath"] = model_path + if require_pull_request is not UNSET: + field_dict["requirePullRequest"] = require_pull_request + if ssh_url is not UNSET: + field_dict["sshUrl"] = ssh_url + if token is not UNSET: + field_dict["token"] = token + if web_url is not UNSET: + field_dict["webUrl"] = web_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + _auth_method = d.pop("authMethod", UNSET) + auth_method: ModelsGitCreateBodyAuthMethod | Unset + if isinstance(_auth_method, Unset): + auth_method = UNSET + else: + auth_method = check_models_git_create_body_auth_method(_auth_method) + + base_branch = d.pop("baseBranch", UNSET) + + branch_per_pull_request = d.pop("branchPerPullRequest", UNSET) + + clone_url = d.pop("cloneUrl", UNSET) + + git_follower = d.pop("gitFollower", UNSET) + + _git_service_provider = d.pop("gitServiceProvider", UNSET) + git_service_provider: ModelsGitCreateBodyGitServiceProvider | Unset + if isinstance(_git_service_provider, Unset): + git_service_provider = UNSET + else: + git_service_provider = check_models_git_create_body_git_service_provider(_git_service_provider) + + model_path = d.pop("modelPath", UNSET) + + _require_pull_request = d.pop("requirePullRequest", UNSET) + require_pull_request: ModelsGitCreateBodyRequirePullRequest | Unset + if isinstance(_require_pull_request, Unset): + require_pull_request = UNSET + else: + require_pull_request = check_models_git_create_body_require_pull_request(_require_pull_request) + + ssh_url = d.pop("sshUrl", UNSET) + + token = d.pop("token", UNSET) + + web_url = d.pop("webUrl", UNSET) + + models_git_create_body = cls( + auth_method=auth_method, + base_branch=base_branch, + branch_per_pull_request=branch_per_pull_request, + clone_url=clone_url, + git_follower=git_follower, + git_service_provider=git_service_provider, + model_path=model_path, + require_pull_request=require_pull_request, + ssh_url=ssh_url, + token=token, + web_url=web_url, + ) + + models_git_create_body.additional_properties = d + return models_git_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_git_create_body_auth_method.py b/omni_python_sdk/models/models_git_create_body_auth_method.py new file mode 100644 index 0000000..163383e --- /dev/null +++ b/omni_python_sdk/models/models_git_create_body_auth_method.py @@ -0,0 +1,14 @@ +from typing import Literal + +ModelsGitCreateBodyAuthMethod = Literal["https_token", "ssh"] + +MODELS_GIT_CREATE_BODY_AUTH_METHOD_VALUES: set[ModelsGitCreateBodyAuthMethod] = { + "https_token", + "ssh", +} + + +def check_models_git_create_body_auth_method(value: str) -> ModelsGitCreateBodyAuthMethod: + if value in MODELS_GIT_CREATE_BODY_AUTH_METHOD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_GIT_CREATE_BODY_AUTH_METHOD_VALUES!r}") diff --git a/omni_python_sdk/models/models_git_create_body_git_service_provider.py b/omni_python_sdk/models/models_git_create_body_git_service_provider.py new file mode 100644 index 0000000..f424d21 --- /dev/null +++ b/omni_python_sdk/models/models_git_create_body_git_service_provider.py @@ -0,0 +1,22 @@ +from typing import Literal + +ModelsGitCreateBodyGitServiceProvider = Literal[ + "auto", "azure_devops", "bitbucket", "bitbucket_datacenter", "github", "gitlab" +] + +MODELS_GIT_CREATE_BODY_GIT_SERVICE_PROVIDER_VALUES: set[ModelsGitCreateBodyGitServiceProvider] = { + "auto", + "azure_devops", + "bitbucket", + "bitbucket_datacenter", + "github", + "gitlab", +} + + +def check_models_git_create_body_git_service_provider(value: str) -> ModelsGitCreateBodyGitServiceProvider: + if value in MODELS_GIT_CREATE_BODY_GIT_SERVICE_PROVIDER_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {MODELS_GIT_CREATE_BODY_GIT_SERVICE_PROVIDER_VALUES!r}" + ) diff --git a/omni_python_sdk/models/models_git_create_body_require_pull_request.py b/omni_python_sdk/models/models_git_create_body_require_pull_request.py new file mode 100644 index 0000000..4912c79 --- /dev/null +++ b/omni_python_sdk/models/models_git_create_body_require_pull_request.py @@ -0,0 +1,17 @@ +from typing import Literal + +ModelsGitCreateBodyRequirePullRequest = Literal["always", "never", "users-only"] + +MODELS_GIT_CREATE_BODY_REQUIRE_PULL_REQUEST_VALUES: set[ModelsGitCreateBodyRequirePullRequest] = { + "always", + "never", + "users-only", +} + + +def check_models_git_create_body_require_pull_request(value: str) -> ModelsGitCreateBodyRequirePullRequest: + if value in MODELS_GIT_CREATE_BODY_REQUIRE_PULL_REQUEST_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {MODELS_GIT_CREATE_BODY_REQUIRE_PULL_REQUEST_VALUES!r}" + ) diff --git a/omni_python_sdk/models/models_git_create_response.py b/omni_python_sdk/models/models_git_create_response.py new file mode 100644 index 0000000..10dc10f --- /dev/null +++ b/omni_python_sdk/models/models_git_create_response.py @@ -0,0 +1,194 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.models_git_create_response_auth_method import ( + ModelsGitCreateResponseAuthMethod, + check_models_git_create_response_auth_method, +) +from ..models.models_git_create_response_require_pull_request import ( + ModelsGitCreateResponseRequirePullRequest, + check_models_git_create_response_require_pull_request, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsGitCreateResponse") + + +@_attrs_define +class ModelsGitCreateResponse: + """ + Attributes: + auth_method (ModelsGitCreateResponseAuthMethod): Authentication method. "ssh" for deploy key, "https_token" for + deploy token/PAT. Example: ssh. + base_branch (str): The target branch for Omni pull requests Example: main. + branch_per_pull_request (bool): If true, all pull requests will create a branch in Omni, even those created + outside of the tool + clone_url (str): Clone URL of the git repository (SSH or HTTPS) Example: git@github.com:org/repo.git. + git_follower (bool): If true, the shared model is read-only and can only be updated by merging pull requests to + the base branch + git_service_provider (str): The git provider type Example: github. + model_path (None | str): Path to model files in the repository Example: omni/my_model. + public_key (None | str): SSH public key for repository access (deploy key). Null for HTTPS token auth. Example: + ssh-ed25519 AAAA.... + require_pull_request (ModelsGitCreateResponseRequirePullRequest): When pull requests are required: "always" for + all changes, "users-only" for user-initiated changes only, "never" for direct commits. Example: users-only. + ssh_url (str): Deprecated — use cloneUrl. Clone URL of the git repository. + web_url (None | str): Custom web URL for the git repository, or null if not set Example: + https://github.com/org/repo. + webhook_url (str): Webhook URL to configure in your git provider Example: + https://app.omni.co/api/webhooks/model/.... + webhook_secret (str | Unset): Webhook secret for signature verification. Only included if requested via + ?include=webhookSecret + """ + + auth_method: ModelsGitCreateResponseAuthMethod + base_branch: str + branch_per_pull_request: bool + clone_url: str + git_follower: bool + git_service_provider: str + model_path: None | str + public_key: None | str + require_pull_request: ModelsGitCreateResponseRequirePullRequest + ssh_url: str + web_url: None | str + webhook_url: str + webhook_secret: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + auth_method: str = self.auth_method + + base_branch = self.base_branch + + branch_per_pull_request = self.branch_per_pull_request + + clone_url = self.clone_url + + git_follower = self.git_follower + + git_service_provider = self.git_service_provider + + model_path: None | str + model_path = self.model_path + + public_key: None | str + public_key = self.public_key + + require_pull_request: str = self.require_pull_request + + ssh_url = self.ssh_url + + web_url: None | str + web_url = self.web_url + + webhook_url = self.webhook_url + + webhook_secret = self.webhook_secret + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "authMethod": auth_method, + "baseBranch": base_branch, + "branchPerPullRequest": branch_per_pull_request, + "cloneUrl": clone_url, + "gitFollower": git_follower, + "gitServiceProvider": git_service_provider, + "modelPath": model_path, + "publicKey": public_key, + "requirePullRequest": require_pull_request, + "sshUrl": ssh_url, + "webUrl": web_url, + "webhookUrl": webhook_url, + } + ) + if webhook_secret is not UNSET: + field_dict["webhookSecret"] = webhook_secret + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + auth_method = check_models_git_create_response_auth_method(d.pop("authMethod")) + + base_branch = d.pop("baseBranch") + + branch_per_pull_request = d.pop("branchPerPullRequest") + + clone_url = d.pop("cloneUrl") + + git_follower = d.pop("gitFollower") + + git_service_provider = d.pop("gitServiceProvider") + + def _parse_model_path(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + model_path = _parse_model_path(d.pop("modelPath")) + + def _parse_public_key(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + public_key = _parse_public_key(d.pop("publicKey")) + + require_pull_request = check_models_git_create_response_require_pull_request(d.pop("requirePullRequest")) + + ssh_url = d.pop("sshUrl") + + def _parse_web_url(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + web_url = _parse_web_url(d.pop("webUrl")) + + webhook_url = d.pop("webhookUrl") + + webhook_secret = d.pop("webhookSecret", UNSET) + + models_git_create_response = cls( + auth_method=auth_method, + base_branch=base_branch, + branch_per_pull_request=branch_per_pull_request, + clone_url=clone_url, + git_follower=git_follower, + git_service_provider=git_service_provider, + model_path=model_path, + public_key=public_key, + require_pull_request=require_pull_request, + ssh_url=ssh_url, + web_url=web_url, + webhook_url=webhook_url, + webhook_secret=webhook_secret, + ) + + models_git_create_response.additional_properties = d + return models_git_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_git_create_response_auth_method.py b/omni_python_sdk/models/models_git_create_response_auth_method.py new file mode 100644 index 0000000..2b8f162 --- /dev/null +++ b/omni_python_sdk/models/models_git_create_response_auth_method.py @@ -0,0 +1,14 @@ +from typing import Literal + +ModelsGitCreateResponseAuthMethod = Literal["https_token", "ssh"] + +MODELS_GIT_CREATE_RESPONSE_AUTH_METHOD_VALUES: set[ModelsGitCreateResponseAuthMethod] = { + "https_token", + "ssh", +} + + +def check_models_git_create_response_auth_method(value: str) -> ModelsGitCreateResponseAuthMethod: + if value in MODELS_GIT_CREATE_RESPONSE_AUTH_METHOD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_GIT_CREATE_RESPONSE_AUTH_METHOD_VALUES!r}") diff --git a/omni_python_sdk/models/models_git_create_response_require_pull_request.py b/omni_python_sdk/models/models_git_create_response_require_pull_request.py new file mode 100644 index 0000000..0b78be0 --- /dev/null +++ b/omni_python_sdk/models/models_git_create_response_require_pull_request.py @@ -0,0 +1,17 @@ +from typing import Literal + +ModelsGitCreateResponseRequirePullRequest = Literal["always", "never", "users-only"] + +MODELS_GIT_CREATE_RESPONSE_REQUIRE_PULL_REQUEST_VALUES: set[ModelsGitCreateResponseRequirePullRequest] = { + "always", + "never", + "users-only", +} + + +def check_models_git_create_response_require_pull_request(value: str) -> ModelsGitCreateResponseRequirePullRequest: + if value in MODELS_GIT_CREATE_RESPONSE_REQUIRE_PULL_REQUEST_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {MODELS_GIT_CREATE_RESPONSE_REQUIRE_PULL_REQUEST_VALUES!r}" + ) diff --git a/omni_python_sdk/models/models_git_delete_response.py b/omni_python_sdk/models/models_git_delete_response.py new file mode 100644 index 0000000..cf87382 --- /dev/null +++ b/omni_python_sdk/models/models_git_delete_response.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsGitDeleteResponse") + + +@_attrs_define +class ModelsGitDeleteResponse: + """ + Attributes: + message (str): Success message Example: Git repository unlinked successfully. + success (bool): Whether the operation succeeded Example: True. + """ + + message: str + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + success = d.pop("success") + + models_git_delete_response = cls( + message=message, + success=success, + ) + + models_git_delete_response.additional_properties = d + return models_git_delete_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_git_get_response.py b/omni_python_sdk/models/models_git_get_response.py new file mode 100644 index 0000000..2cd2eab --- /dev/null +++ b/omni_python_sdk/models/models_git_get_response.py @@ -0,0 +1,194 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.models_git_get_response_auth_method import ( + ModelsGitGetResponseAuthMethod, + check_models_git_get_response_auth_method, +) +from ..models.models_git_get_response_require_pull_request import ( + ModelsGitGetResponseRequirePullRequest, + check_models_git_get_response_require_pull_request, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsGitGetResponse") + + +@_attrs_define +class ModelsGitGetResponse: + """ + Attributes: + auth_method (ModelsGitGetResponseAuthMethod): Authentication method. "ssh" for deploy key, "https_token" for + deploy token/PAT. Example: ssh. + base_branch (str): The target branch for Omni pull requests Example: main. + branch_per_pull_request (bool): If true, all pull requests will create a branch in Omni, even those created + outside of the tool + clone_url (str): Clone URL of the git repository (SSH or HTTPS) Example: git@github.com:org/repo.git. + git_follower (bool): If true, the shared model is read-only and can only be updated by merging pull requests to + the base branch + git_service_provider (str): The git provider type Example: github. + model_path (None | str): Path to model files in the repository Example: omni/my_model. + public_key (None | str): SSH public key for repository access (deploy key). Null for HTTPS token auth. Example: + ssh-ed25519 AAAA.... + require_pull_request (ModelsGitGetResponseRequirePullRequest): When pull requests are required: "always" for all + changes, "users-only" for user-initiated changes only, "never" for direct commits. Example: users-only. + ssh_url (str): Deprecated — use cloneUrl. Clone URL of the git repository. + web_url (None | str): Custom web URL for the git repository, or null if not set Example: + https://github.com/org/repo. + webhook_url (str): Webhook URL to configure in your git provider Example: + https://app.omni.co/api/webhooks/model/.... + webhook_secret (str | Unset): Webhook secret for signature verification. Only included if requested via + ?include=webhookSecret + """ + + auth_method: ModelsGitGetResponseAuthMethod + base_branch: str + branch_per_pull_request: bool + clone_url: str + git_follower: bool + git_service_provider: str + model_path: None | str + public_key: None | str + require_pull_request: ModelsGitGetResponseRequirePullRequest + ssh_url: str + web_url: None | str + webhook_url: str + webhook_secret: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + auth_method: str = self.auth_method + + base_branch = self.base_branch + + branch_per_pull_request = self.branch_per_pull_request + + clone_url = self.clone_url + + git_follower = self.git_follower + + git_service_provider = self.git_service_provider + + model_path: None | str + model_path = self.model_path + + public_key: None | str + public_key = self.public_key + + require_pull_request: str = self.require_pull_request + + ssh_url = self.ssh_url + + web_url: None | str + web_url = self.web_url + + webhook_url = self.webhook_url + + webhook_secret = self.webhook_secret + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "authMethod": auth_method, + "baseBranch": base_branch, + "branchPerPullRequest": branch_per_pull_request, + "cloneUrl": clone_url, + "gitFollower": git_follower, + "gitServiceProvider": git_service_provider, + "modelPath": model_path, + "publicKey": public_key, + "requirePullRequest": require_pull_request, + "sshUrl": ssh_url, + "webUrl": web_url, + "webhookUrl": webhook_url, + } + ) + if webhook_secret is not UNSET: + field_dict["webhookSecret"] = webhook_secret + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + auth_method = check_models_git_get_response_auth_method(d.pop("authMethod")) + + base_branch = d.pop("baseBranch") + + branch_per_pull_request = d.pop("branchPerPullRequest") + + clone_url = d.pop("cloneUrl") + + git_follower = d.pop("gitFollower") + + git_service_provider = d.pop("gitServiceProvider") + + def _parse_model_path(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + model_path = _parse_model_path(d.pop("modelPath")) + + def _parse_public_key(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + public_key = _parse_public_key(d.pop("publicKey")) + + require_pull_request = check_models_git_get_response_require_pull_request(d.pop("requirePullRequest")) + + ssh_url = d.pop("sshUrl") + + def _parse_web_url(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + web_url = _parse_web_url(d.pop("webUrl")) + + webhook_url = d.pop("webhookUrl") + + webhook_secret = d.pop("webhookSecret", UNSET) + + models_git_get_response = cls( + auth_method=auth_method, + base_branch=base_branch, + branch_per_pull_request=branch_per_pull_request, + clone_url=clone_url, + git_follower=git_follower, + git_service_provider=git_service_provider, + model_path=model_path, + public_key=public_key, + require_pull_request=require_pull_request, + ssh_url=ssh_url, + web_url=web_url, + webhook_url=webhook_url, + webhook_secret=webhook_secret, + ) + + models_git_get_response.additional_properties = d + return models_git_get_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_git_get_response_auth_method.py b/omni_python_sdk/models/models_git_get_response_auth_method.py new file mode 100644 index 0000000..71daba7 --- /dev/null +++ b/omni_python_sdk/models/models_git_get_response_auth_method.py @@ -0,0 +1,14 @@ +from typing import Literal + +ModelsGitGetResponseAuthMethod = Literal["https_token", "ssh"] + +MODELS_GIT_GET_RESPONSE_AUTH_METHOD_VALUES: set[ModelsGitGetResponseAuthMethod] = { + "https_token", + "ssh", +} + + +def check_models_git_get_response_auth_method(value: str) -> ModelsGitGetResponseAuthMethod: + if value in MODELS_GIT_GET_RESPONSE_AUTH_METHOD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_GIT_GET_RESPONSE_AUTH_METHOD_VALUES!r}") diff --git a/omni_python_sdk/models/models_git_get_response_require_pull_request.py b/omni_python_sdk/models/models_git_get_response_require_pull_request.py new file mode 100644 index 0000000..1d27d44 --- /dev/null +++ b/omni_python_sdk/models/models_git_get_response_require_pull_request.py @@ -0,0 +1,17 @@ +from typing import Literal + +ModelsGitGetResponseRequirePullRequest = Literal["always", "never", "users-only"] + +MODELS_GIT_GET_RESPONSE_REQUIRE_PULL_REQUEST_VALUES: set[ModelsGitGetResponseRequirePullRequest] = { + "always", + "never", + "users-only", +} + + +def check_models_git_get_response_require_pull_request(value: str) -> ModelsGitGetResponseRequirePullRequest: + if value in MODELS_GIT_GET_RESPONSE_REQUIRE_PULL_REQUEST_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {MODELS_GIT_GET_RESPONSE_REQUIRE_PULL_REQUEST_VALUES!r}" + ) diff --git a/omni_python_sdk/models/models_git_sync_body.py b/omni_python_sdk/models/models_git_sync_body.py new file mode 100644 index 0000000..c9073bc --- /dev/null +++ b/omni_python_sdk/models/models_git_sync_body.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsGitSyncBody") + + +@_attrs_define +class ModelsGitSyncBody: + """ + Attributes: + commit_message (str | Unset): Optional commit message for the git sync operation Example: Update model schema. + """ + + commit_message: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + commit_message = self.commit_message + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if commit_message is not UNSET: + field_dict["commitMessage"] = commit_message + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + commit_message = d.pop("commitMessage", UNSET) + + models_git_sync_body = cls( + commit_message=commit_message, + ) + + models_git_sync_body.additional_properties = d + return models_git_sync_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_git_sync_response.py b/omni_python_sdk/models/models_git_sync_response.py new file mode 100644 index 0000000..ddd1eb1 --- /dev/null +++ b/omni_python_sdk/models/models_git_sync_response.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsGitSyncResponse") + + +@_attrs_define +class ModelsGitSyncResponse: + """ + Attributes: + did_sync (bool): Whether a sync operation was performed + git_sha (None | str): The git SHA after the sync operation + in_sync (bool): Whether the model is currently in sync with git + message (str): Human-readable message about the sync status + """ + + did_sync: bool + git_sha: None | str + in_sync: bool + message: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + did_sync = self.did_sync + + git_sha: None | str + git_sha = self.git_sha + + in_sync = self.in_sync + + message = self.message + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "didSync": did_sync, + "gitSha": git_sha, + "inSync": in_sync, + "message": message, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + did_sync = d.pop("didSync") + + def _parse_git_sha(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + git_sha = _parse_git_sha(d.pop("gitSha")) + + in_sync = d.pop("inSync") + + message = d.pop("message") + + models_git_sync_response = cls( + did_sync=did_sync, + git_sha=git_sha, + in_sync=in_sync, + message=message, + ) + + models_git_sync_response.additional_properties = d + return models_git_sync_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_git_update_body.py b/omni_python_sdk/models/models_git_update_body.py new file mode 100644 index 0000000..d56b3af --- /dev/null +++ b/omni_python_sdk/models/models_git_update_body.py @@ -0,0 +1,187 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.models_git_update_body_auth_method import ( + ModelsGitUpdateBodyAuthMethod, + check_models_git_update_body_auth_method, +) +from ..models.models_git_update_body_git_service_provider import ( + ModelsGitUpdateBodyGitServiceProvider, + check_models_git_update_body_git_service_provider, +) +from ..models.models_git_update_body_require_pull_request import ( + ModelsGitUpdateBodyRequirePullRequest, + check_models_git_update_body_require_pull_request, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsGitUpdateBody") + + +@_attrs_define +class ModelsGitUpdateBody: + """ + Attributes: + auth_method (ModelsGitUpdateBodyAuthMethod | Unset): Authentication method to change to. Example: ssh. + base_branch (str | Unset): The target branch for Omni pull requests Example: main. + branch_per_pull_request (bool | Unset): If true, all pull requests will create a branch in Omni + clone_url (str | Unset): Clone URL of the git repository (SSH or HTTPS). Example: git@github.com:org/repo.git. + git_follower (bool | Unset): If true, the shared model will be read-only + git_service_provider (ModelsGitUpdateBodyGitServiceProvider | Unset): The git provider type Example: github. + model_path (str | Unset): Path to model files in the repository Example: my_model. + require_pull_request (ModelsGitUpdateBodyRequirePullRequest | Unset): Controls when pull requests are required + Example: users-only. + ssh_url (str | Unset): Deprecated — use cloneUrl. Clone URL of the git repository. Example: + git@github.com:org/repo.git. + token (str | Unset): HTTPS token for authentication (deploy token value, PAT, etc.). + web_url (str | Unset): Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC + and differs from the inferred HTTPS address Example: https://github.com/org/repo. + """ + + auth_method: ModelsGitUpdateBodyAuthMethod | Unset = UNSET + base_branch: str | Unset = UNSET + branch_per_pull_request: bool | Unset = UNSET + clone_url: str | Unset = UNSET + git_follower: bool | Unset = UNSET + git_service_provider: ModelsGitUpdateBodyGitServiceProvider | Unset = UNSET + model_path: str | Unset = UNSET + require_pull_request: ModelsGitUpdateBodyRequirePullRequest | Unset = UNSET + ssh_url: str | Unset = UNSET + token: str | Unset = UNSET + web_url: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + auth_method: str | Unset = UNSET + if not isinstance(self.auth_method, Unset): + auth_method = self.auth_method + + base_branch = self.base_branch + + branch_per_pull_request = self.branch_per_pull_request + + clone_url = self.clone_url + + git_follower = self.git_follower + + git_service_provider: str | Unset = UNSET + if not isinstance(self.git_service_provider, Unset): + git_service_provider = self.git_service_provider + + model_path = self.model_path + + require_pull_request: str | Unset = UNSET + if not isinstance(self.require_pull_request, Unset): + require_pull_request = self.require_pull_request + + ssh_url = self.ssh_url + + token = self.token + + web_url = self.web_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if auth_method is not UNSET: + field_dict["authMethod"] = auth_method + if base_branch is not UNSET: + field_dict["baseBranch"] = base_branch + if branch_per_pull_request is not UNSET: + field_dict["branchPerPullRequest"] = branch_per_pull_request + if clone_url is not UNSET: + field_dict["cloneUrl"] = clone_url + if git_follower is not UNSET: + field_dict["gitFollower"] = git_follower + if git_service_provider is not UNSET: + field_dict["gitServiceProvider"] = git_service_provider + if model_path is not UNSET: + field_dict["modelPath"] = model_path + if require_pull_request is not UNSET: + field_dict["requirePullRequest"] = require_pull_request + if ssh_url is not UNSET: + field_dict["sshUrl"] = ssh_url + if token is not UNSET: + field_dict["token"] = token + if web_url is not UNSET: + field_dict["webUrl"] = web_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + _auth_method = d.pop("authMethod", UNSET) + auth_method: ModelsGitUpdateBodyAuthMethod | Unset + if isinstance(_auth_method, Unset): + auth_method = UNSET + else: + auth_method = check_models_git_update_body_auth_method(_auth_method) + + base_branch = d.pop("baseBranch", UNSET) + + branch_per_pull_request = d.pop("branchPerPullRequest", UNSET) + + clone_url = d.pop("cloneUrl", UNSET) + + git_follower = d.pop("gitFollower", UNSET) + + _git_service_provider = d.pop("gitServiceProvider", UNSET) + git_service_provider: ModelsGitUpdateBodyGitServiceProvider | Unset + if isinstance(_git_service_provider, Unset): + git_service_provider = UNSET + else: + git_service_provider = check_models_git_update_body_git_service_provider(_git_service_provider) + + model_path = d.pop("modelPath", UNSET) + + _require_pull_request = d.pop("requirePullRequest", UNSET) + require_pull_request: ModelsGitUpdateBodyRequirePullRequest | Unset + if isinstance(_require_pull_request, Unset): + require_pull_request = UNSET + else: + require_pull_request = check_models_git_update_body_require_pull_request(_require_pull_request) + + ssh_url = d.pop("sshUrl", UNSET) + + token = d.pop("token", UNSET) + + web_url = d.pop("webUrl", UNSET) + + models_git_update_body = cls( + auth_method=auth_method, + base_branch=base_branch, + branch_per_pull_request=branch_per_pull_request, + clone_url=clone_url, + git_follower=git_follower, + git_service_provider=git_service_provider, + model_path=model_path, + require_pull_request=require_pull_request, + ssh_url=ssh_url, + token=token, + web_url=web_url, + ) + + models_git_update_body.additional_properties = d + return models_git_update_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_git_update_body_auth_method.py b/omni_python_sdk/models/models_git_update_body_auth_method.py new file mode 100644 index 0000000..f230705 --- /dev/null +++ b/omni_python_sdk/models/models_git_update_body_auth_method.py @@ -0,0 +1,14 @@ +from typing import Literal + +ModelsGitUpdateBodyAuthMethod = Literal["https_token", "ssh"] + +MODELS_GIT_UPDATE_BODY_AUTH_METHOD_VALUES: set[ModelsGitUpdateBodyAuthMethod] = { + "https_token", + "ssh", +} + + +def check_models_git_update_body_auth_method(value: str) -> ModelsGitUpdateBodyAuthMethod: + if value in MODELS_GIT_UPDATE_BODY_AUTH_METHOD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_GIT_UPDATE_BODY_AUTH_METHOD_VALUES!r}") diff --git a/omni_python_sdk/models/models_git_update_body_git_service_provider.py b/omni_python_sdk/models/models_git_update_body_git_service_provider.py new file mode 100644 index 0000000..17cafa2 --- /dev/null +++ b/omni_python_sdk/models/models_git_update_body_git_service_provider.py @@ -0,0 +1,22 @@ +from typing import Literal + +ModelsGitUpdateBodyGitServiceProvider = Literal[ + "auto", "azure_devops", "bitbucket", "bitbucket_datacenter", "github", "gitlab" +] + +MODELS_GIT_UPDATE_BODY_GIT_SERVICE_PROVIDER_VALUES: set[ModelsGitUpdateBodyGitServiceProvider] = { + "auto", + "azure_devops", + "bitbucket", + "bitbucket_datacenter", + "github", + "gitlab", +} + + +def check_models_git_update_body_git_service_provider(value: str) -> ModelsGitUpdateBodyGitServiceProvider: + if value in MODELS_GIT_UPDATE_BODY_GIT_SERVICE_PROVIDER_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {MODELS_GIT_UPDATE_BODY_GIT_SERVICE_PROVIDER_VALUES!r}" + ) diff --git a/omni_python_sdk/models/models_git_update_body_require_pull_request.py b/omni_python_sdk/models/models_git_update_body_require_pull_request.py new file mode 100644 index 0000000..75856df --- /dev/null +++ b/omni_python_sdk/models/models_git_update_body_require_pull_request.py @@ -0,0 +1,17 @@ +from typing import Literal + +ModelsGitUpdateBodyRequirePullRequest = Literal["always", "never", "users-only"] + +MODELS_GIT_UPDATE_BODY_REQUIRE_PULL_REQUEST_VALUES: set[ModelsGitUpdateBodyRequirePullRequest] = { + "always", + "never", + "users-only", +} + + +def check_models_git_update_body_require_pull_request(value: str) -> ModelsGitUpdateBodyRequirePullRequest: + if value in MODELS_GIT_UPDATE_BODY_REQUIRE_PULL_REQUEST_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {MODELS_GIT_UPDATE_BODY_REQUIRE_PULL_REQUEST_VALUES!r}" + ) diff --git a/omni_python_sdk/models/models_git_update_response.py b/omni_python_sdk/models/models_git_update_response.py new file mode 100644 index 0000000..b7340e1 --- /dev/null +++ b/omni_python_sdk/models/models_git_update_response.py @@ -0,0 +1,194 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.models_git_update_response_auth_method import ( + ModelsGitUpdateResponseAuthMethod, + check_models_git_update_response_auth_method, +) +from ..models.models_git_update_response_require_pull_request import ( + ModelsGitUpdateResponseRequirePullRequest, + check_models_git_update_response_require_pull_request, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsGitUpdateResponse") + + +@_attrs_define +class ModelsGitUpdateResponse: + """ + Attributes: + auth_method (ModelsGitUpdateResponseAuthMethod): Authentication method. "ssh" for deploy key, "https_token" for + deploy token/PAT. Example: ssh. + base_branch (str): The target branch for Omni pull requests Example: main. + branch_per_pull_request (bool): If true, all pull requests will create a branch in Omni, even those created + outside of the tool + clone_url (str): Clone URL of the git repository (SSH or HTTPS) Example: git@github.com:org/repo.git. + git_follower (bool): If true, the shared model is read-only and can only be updated by merging pull requests to + the base branch + git_service_provider (str): The git provider type Example: github. + model_path (None | str): Path to model files in the repository Example: omni/my_model. + public_key (None | str): SSH public key for repository access (deploy key). Null for HTTPS token auth. Example: + ssh-ed25519 AAAA.... + require_pull_request (ModelsGitUpdateResponseRequirePullRequest): When pull requests are required: "always" for + all changes, "users-only" for user-initiated changes only, "never" for direct commits. Example: users-only. + ssh_url (str): Deprecated — use cloneUrl. Clone URL of the git repository. + web_url (None | str): Custom web URL for the git repository, or null if not set Example: + https://github.com/org/repo. + webhook_url (str): Webhook URL to configure in your git provider Example: + https://app.omni.co/api/webhooks/model/.... + webhook_secret (str | Unset): Webhook secret for signature verification. Only included if requested via + ?include=webhookSecret + """ + + auth_method: ModelsGitUpdateResponseAuthMethod + base_branch: str + branch_per_pull_request: bool + clone_url: str + git_follower: bool + git_service_provider: str + model_path: None | str + public_key: None | str + require_pull_request: ModelsGitUpdateResponseRequirePullRequest + ssh_url: str + web_url: None | str + webhook_url: str + webhook_secret: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + auth_method: str = self.auth_method + + base_branch = self.base_branch + + branch_per_pull_request = self.branch_per_pull_request + + clone_url = self.clone_url + + git_follower = self.git_follower + + git_service_provider = self.git_service_provider + + model_path: None | str + model_path = self.model_path + + public_key: None | str + public_key = self.public_key + + require_pull_request: str = self.require_pull_request + + ssh_url = self.ssh_url + + web_url: None | str + web_url = self.web_url + + webhook_url = self.webhook_url + + webhook_secret = self.webhook_secret + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "authMethod": auth_method, + "baseBranch": base_branch, + "branchPerPullRequest": branch_per_pull_request, + "cloneUrl": clone_url, + "gitFollower": git_follower, + "gitServiceProvider": git_service_provider, + "modelPath": model_path, + "publicKey": public_key, + "requirePullRequest": require_pull_request, + "sshUrl": ssh_url, + "webUrl": web_url, + "webhookUrl": webhook_url, + } + ) + if webhook_secret is not UNSET: + field_dict["webhookSecret"] = webhook_secret + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + auth_method = check_models_git_update_response_auth_method(d.pop("authMethod")) + + base_branch = d.pop("baseBranch") + + branch_per_pull_request = d.pop("branchPerPullRequest") + + clone_url = d.pop("cloneUrl") + + git_follower = d.pop("gitFollower") + + git_service_provider = d.pop("gitServiceProvider") + + def _parse_model_path(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + model_path = _parse_model_path(d.pop("modelPath")) + + def _parse_public_key(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + public_key = _parse_public_key(d.pop("publicKey")) + + require_pull_request = check_models_git_update_response_require_pull_request(d.pop("requirePullRequest")) + + ssh_url = d.pop("sshUrl") + + def _parse_web_url(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + web_url = _parse_web_url(d.pop("webUrl")) + + webhook_url = d.pop("webhookUrl") + + webhook_secret = d.pop("webhookSecret", UNSET) + + models_git_update_response = cls( + auth_method=auth_method, + base_branch=base_branch, + branch_per_pull_request=branch_per_pull_request, + clone_url=clone_url, + git_follower=git_follower, + git_service_provider=git_service_provider, + model_path=model_path, + public_key=public_key, + require_pull_request=require_pull_request, + ssh_url=ssh_url, + web_url=web_url, + webhook_url=webhook_url, + webhook_secret=webhook_secret, + ) + + models_git_update_response.additional_properties = d + return models_git_update_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_git_update_response_auth_method.py b/omni_python_sdk/models/models_git_update_response_auth_method.py new file mode 100644 index 0000000..78010a4 --- /dev/null +++ b/omni_python_sdk/models/models_git_update_response_auth_method.py @@ -0,0 +1,14 @@ +from typing import Literal + +ModelsGitUpdateResponseAuthMethod = Literal["https_token", "ssh"] + +MODELS_GIT_UPDATE_RESPONSE_AUTH_METHOD_VALUES: set[ModelsGitUpdateResponseAuthMethod] = { + "https_token", + "ssh", +} + + +def check_models_git_update_response_auth_method(value: str) -> ModelsGitUpdateResponseAuthMethod: + if value in MODELS_GIT_UPDATE_RESPONSE_AUTH_METHOD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_GIT_UPDATE_RESPONSE_AUTH_METHOD_VALUES!r}") diff --git a/omni_python_sdk/models/models_git_update_response_require_pull_request.py b/omni_python_sdk/models/models_git_update_response_require_pull_request.py new file mode 100644 index 0000000..c307057 --- /dev/null +++ b/omni_python_sdk/models/models_git_update_response_require_pull_request.py @@ -0,0 +1,17 @@ +from typing import Literal + +ModelsGitUpdateResponseRequirePullRequest = Literal["always", "never", "users-only"] + +MODELS_GIT_UPDATE_RESPONSE_REQUIRE_PULL_REQUEST_VALUES: set[ModelsGitUpdateResponseRequirePullRequest] = { + "always", + "never", + "users-only", +} + + +def check_models_git_update_response_require_pull_request(value: str) -> ModelsGitUpdateResponseRequirePullRequest: + if value in MODELS_GIT_UPDATE_RESPONSE_REQUIRE_PULL_REQUEST_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {MODELS_GIT_UPDATE_RESPONSE_REQUIRE_PULL_REQUEST_VALUES!r}" + ) diff --git a/omni_python_sdk/models/models_list_include_deleted.py b/omni_python_sdk/models/models_list_include_deleted.py new file mode 100644 index 0000000..4ec72fe --- /dev/null +++ b/omni_python_sdk/models/models_list_include_deleted.py @@ -0,0 +1,16 @@ +from typing import Literal + +ModelsListIncludeDeleted = Literal["0", "1", "false", "true"] + +MODELS_LIST_INCLUDE_DELETED_VALUES: set[ModelsListIncludeDeleted] = { + "0", + "1", + "false", + "true", +} + + +def check_models_list_include_deleted(value: str) -> ModelsListIncludeDeleted: + if value in MODELS_LIST_INCLUDE_DELETED_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_LIST_INCLUDE_DELETED_VALUES!r}") diff --git a/omni_python_sdk/models/models_list_model_kind.py b/omni_python_sdk/models/models_list_model_kind.py new file mode 100644 index 0000000..b5086ef --- /dev/null +++ b/omni_python_sdk/models/models_list_model_kind.py @@ -0,0 +1,18 @@ +from typing import Literal + +ModelsListModelKind = Literal["BRANCH", "QUERY", "SCHEMA", "SHARED", "SHARED_EXTENSION", "WORKBOOK"] + +MODELS_LIST_MODEL_KIND_VALUES: set[ModelsListModelKind] = { + "BRANCH", + "QUERY", + "SCHEMA", + "SHARED", + "SHARED_EXTENSION", + "WORKBOOK", +} + + +def check_models_list_model_kind(value: str) -> ModelsListModelKind: + if value in MODELS_LIST_MODEL_KIND_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_LIST_MODEL_KIND_VALUES!r}") diff --git a/omni_python_sdk/models/models_list_response.py b/omni_python_sdk/models/models_list_response.py new file mode 100644 index 0000000..b826ce9 --- /dev/null +++ b/omni_python_sdk/models/models_list_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.models_list_response_records_item import ModelsListResponseRecordsItem + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="ModelsListResponse") + + +@_attrs_define +class ModelsListResponse: + """ + Attributes: + page_info (PageInfo): + records (list[ModelsListResponseRecordsItem]): List of model records + """ + + page_info: PageInfo + records: list[ModelsListResponseRecordsItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_list_response_records_item import ModelsListResponseRecordsItem + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = ModelsListResponseRecordsItem.from_dict(records_item_data) + + records.append(records_item) + + models_list_response = cls( + page_info=page_info, + records=records, + ) + + models_list_response.additional_properties = d + return models_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_list_response_records_item.py b/omni_python_sdk/models/models_list_response_records_item.py new file mode 100644 index 0000000..e76ff83 --- /dev/null +++ b/omni_python_sdk/models/models_list_response_records_item.py @@ -0,0 +1,177 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.models_list_response_records_item_branches_item import ModelsListResponseRecordsItemBranchesItem + + +T = TypeVar("T", bound="ModelsListResponseRecordsItem") + + +@_attrs_define +class ModelsListResponseRecordsItem: + """ + Attributes: + base_model_id (None | str): Base model ID for branch/extension models + connection_id (None | str): Connection ID + created_at (str): Creation timestamp + deleted_at (None | str): Deletion timestamp + id (str): Model ID + model_kind (None | str): Model kind + name (None | str): Model name + updated_at (str): Last update timestamp + branches (list[ModelsListResponseRecordsItemBranchesItem] | Unset): Active branches (if include=activeBranches) + """ + + base_model_id: None | str + connection_id: None | str + created_at: str + deleted_at: None | str + id: str + model_kind: None | str + name: None | str + updated_at: str + branches: list[ModelsListResponseRecordsItemBranchesItem] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + base_model_id: None | str + base_model_id = self.base_model_id + + connection_id: None | str + connection_id = self.connection_id + + created_at = self.created_at + + deleted_at: None | str + deleted_at = self.deleted_at + + id = self.id + + model_kind: None | str + model_kind = self.model_kind + + name: None | str + name = self.name + + updated_at = self.updated_at + + branches: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.branches, Unset): + branches = [] + for branches_item_data in self.branches: + branches_item = branches_item_data.to_dict() + branches.append(branches_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "baseModelId": base_model_id, + "connectionId": connection_id, + "createdAt": created_at, + "deletedAt": deleted_at, + "id": id, + "modelKind": model_kind, + "name": name, + "updatedAt": updated_at, + } + ) + if branches is not UNSET: + field_dict["branches"] = branches + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_list_response_records_item_branches_item import ModelsListResponseRecordsItemBranchesItem + + d = dict(src_dict) + + def _parse_base_model_id(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + base_model_id = _parse_base_model_id(d.pop("baseModelId")) + + def _parse_connection_id(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + connection_id = _parse_connection_id(d.pop("connectionId")) + + created_at = d.pop("createdAt") + + def _parse_deleted_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + deleted_at = _parse_deleted_at(d.pop("deletedAt")) + + id = d.pop("id") + + def _parse_model_kind(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + model_kind = _parse_model_kind(d.pop("modelKind")) + + def _parse_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + name = _parse_name(d.pop("name")) + + updated_at = d.pop("updatedAt") + + _branches = d.pop("branches", UNSET) + branches: list[ModelsListResponseRecordsItemBranchesItem] | Unset = UNSET + if _branches is not UNSET: + branches = [] + for branches_item_data in _branches: + branches_item = ModelsListResponseRecordsItemBranchesItem.from_dict(branches_item_data) + + branches.append(branches_item) + + models_list_response_records_item = cls( + base_model_id=base_model_id, + connection_id=connection_id, + created_at=created_at, + deleted_at=deleted_at, + id=id, + model_kind=model_kind, + name=name, + updated_at=updated_at, + branches=branches, + ) + + models_list_response_records_item.additional_properties = d + return models_list_response_records_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_list_response_records_item_branches_item.py b/omni_python_sdk/models/models_list_response_records_item_branches_item.py new file mode 100644 index 0000000..1ab3749 --- /dev/null +++ b/omni_python_sdk/models/models_list_response_records_item_branches_item.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsListResponseRecordsItemBranchesItem") + + +@_attrs_define +class ModelsListResponseRecordsItemBranchesItem: + """ + Attributes: + id (str): Branch ID + name (str): Branch name + """ + + id: str + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + name = d.pop("name") + + models_list_response_records_item_branches_item = cls( + id=id, + name=name, + ) + + models_list_response_records_item_branches_item.additional_properties = d + return models_list_response_records_item_branches_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_list_sort_direction.py b/omni_python_sdk/models/models_list_sort_direction.py new file mode 100644 index 0000000..178c727 --- /dev/null +++ b/omni_python_sdk/models/models_list_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +ModelsListSortDirection = Literal["asc", "desc"] + +MODELS_LIST_SORT_DIRECTION_VALUES: set[ModelsListSortDirection] = { + "asc", + "desc", +} + + +def check_models_list_sort_direction(value: str) -> ModelsListSortDirection: + if value in MODELS_LIST_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_LIST_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/models_list_sort_field.py b/omni_python_sdk/models/models_list_sort_field.py new file mode 100644 index 0000000..60fa0c5 --- /dev/null +++ b/omni_python_sdk/models/models_list_sort_field.py @@ -0,0 +1,18 @@ +from typing import Literal + +ModelsListSortField = Literal["baseModelId", "connectionId", "createdAt", "modelKind", "name", "updatedAt"] + +MODELS_LIST_SORT_FIELD_VALUES: set[ModelsListSortField] = { + "baseModelId", + "connectionId", + "createdAt", + "modelKind", + "name", + "updatedAt", +} + + +def check_models_list_sort_field(value: str) -> ModelsListSortField: + if value in MODELS_LIST_SORT_FIELD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_LIST_SORT_FIELD_VALUES!r}") diff --git a/omni_python_sdk/models/models_list_topics_response.py b/omni_python_sdk/models/models_list_topics_response.py new file mode 100644 index 0000000..4a8d601 --- /dev/null +++ b/omni_python_sdk/models/models_list_topics_response.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.models_list_topics_response_topics_item import ModelsListTopicsResponseTopicsItem + + +T = TypeVar("T", bound="ModelsListTopicsResponse") + + +@_attrs_define +class ModelsListTopicsResponse: + """ + Attributes: + success (bool): Whether the operation succeeded + topics (list[ModelsListTopicsResponseTopicsItem]): List of topics + """ + + success: bool + topics: list[ModelsListTopicsResponseTopicsItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + topics = [] + for topics_item_data in self.topics: + topics_item = topics_item_data.to_dict() + topics.append(topics_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + "topics": topics, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_list_topics_response_topics_item import ModelsListTopicsResponseTopicsItem + + d = dict(src_dict) + success = d.pop("success") + + topics = [] + _topics = d.pop("topics") + for topics_item_data in _topics: + topics_item = ModelsListTopicsResponseTopicsItem.from_dict(topics_item_data) + + topics.append(topics_item) + + models_list_topics_response = cls( + success=success, + topics=topics, + ) + + models_list_topics_response.additional_properties = d + return models_list_topics_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_list_topics_response_topics_item.py b/omni_python_sdk/models/models_list_topics_response_topics_item.py new file mode 100644 index 0000000..3073ae7 --- /dev/null +++ b/omni_python_sdk/models/models_list_topics_response_topics_item.py @@ -0,0 +1,107 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsListTopicsResponseTopicsItem") + + +@_attrs_define +class ModelsListTopicsResponseTopicsItem: + """ + Attributes: + base_view_name (str): Base view name for the topic + name (str): Topic name + description (str | Unset): Topic description + group_label (str | Unset): Group label + hidden (bool | Unset): Whether the topic is hidden + label (str | Unset): Topic label + """ + + base_view_name: str + name: str + description: str | Unset = UNSET + group_label: str | Unset = UNSET + hidden: bool | Unset = UNSET + label: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + base_view_name = self.base_view_name + + name = self.name + + description = self.description + + group_label = self.group_label + + hidden = self.hidden + + label = self.label + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "base_view_name": base_view_name, + "name": name, + } + ) + if description is not UNSET: + field_dict["description"] = description + if group_label is not UNSET: + field_dict["group_label"] = group_label + if hidden is not UNSET: + field_dict["hidden"] = hidden + if label is not UNSET: + field_dict["label"] = label + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + base_view_name = d.pop("base_view_name") + + name = d.pop("name") + + description = d.pop("description", UNSET) + + group_label = d.pop("group_label", UNSET) + + hidden = d.pop("hidden", UNSET) + + label = d.pop("label", UNSET) + + models_list_topics_response_topics_item = cls( + base_view_name=base_view_name, + name=name, + description=description, + group_label=group_label, + hidden=hidden, + label=label, + ) + + models_list_topics_response_topics_item.additional_properties = d + return models_list_topics_response_topics_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_merge_branch_body.py b/omni_python_sdk/models/models_merge_branch_body.py new file mode 100644 index 0000000..e359ee4 --- /dev/null +++ b/omni_python_sdk/models/models_merge_branch_body.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsMergeBranchBody") + + +@_attrs_define +class ModelsMergeBranchBody: + """ + Attributes: + commit_message (str | Unset): Custom commit message for git sync + delete_branch (bool | Unset): Delete the branch after merging Default: False. + force_override_git_settings (bool | Unset): Override PR-required or git-follower settings Default: False. + publish_drafts (bool | Unset): Publish branch-attached drafts Default: True. + """ + + commit_message: str | Unset = UNSET + delete_branch: bool | Unset = False + force_override_git_settings: bool | Unset = False + publish_drafts: bool | Unset = True + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + commit_message = self.commit_message + + delete_branch = self.delete_branch + + force_override_git_settings = self.force_override_git_settings + + publish_drafts = self.publish_drafts + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if commit_message is not UNSET: + field_dict["commit_message"] = commit_message + if delete_branch is not UNSET: + field_dict["delete_branch"] = delete_branch + if force_override_git_settings is not UNSET: + field_dict["force_override_git_settings"] = force_override_git_settings + if publish_drafts is not UNSET: + field_dict["publish_drafts"] = publish_drafts + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + commit_message = d.pop("commit_message", UNSET) + + delete_branch = d.pop("delete_branch", UNSET) + + force_override_git_settings = d.pop("force_override_git_settings", UNSET) + + publish_drafts = d.pop("publish_drafts", UNSET) + + models_merge_branch_body = cls( + commit_message=commit_message, + delete_branch=delete_branch, + force_override_git_settings=force_override_git_settings, + publish_drafts=publish_drafts, + ) + + models_merge_branch_body.additional_properties = d + return models_merge_branch_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_merge_branch_response.py b/omni_python_sdk/models/models_merge_branch_response.py new file mode 100644 index 0000000..d9e0b6e --- /dev/null +++ b/omni_python_sdk/models/models_merge_branch_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsMergeBranchResponse") + + +@_attrs_define +class ModelsMergeBranchResponse: + """ + Attributes: + failed_drafts_count (float): Number of drafts that failed to publish + git_synced (bool): Whether git was synced + published_drafts_count (float): Number of drafts published + success (bool): Whether the merge succeeded + """ + + failed_drafts_count: float + git_synced: bool + published_drafts_count: float + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + failed_drafts_count = self.failed_drafts_count + + git_synced = self.git_synced + + published_drafts_count = self.published_drafts_count + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "failed_drafts_count": failed_drafts_count, + "git_synced": git_synced, + "published_drafts_count": published_drafts_count, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + failed_drafts_count = d.pop("failed_drafts_count") + + git_synced = d.pop("git_synced") + + published_drafts_count = d.pop("published_drafts_count") + + success = d.pop("success") + + models_merge_branch_response = cls( + failed_drafts_count=failed_drafts_count, + git_synced=git_synced, + published_drafts_count=published_drafts_count, + success=success, + ) + + models_merge_branch_response.additional_properties = d + return models_merge_branch_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_migrate_body.py b/omni_python_sdk/models/models_migrate_body.py new file mode 100644 index 0000000..941e5b5 --- /dev/null +++ b/omni_python_sdk/models/models_migrate_body.py @@ -0,0 +1,103 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsMigrateBody") + + +@_attrs_define +class ModelsMigrateBody: + """ + Attributes: + target_model_id (UUID): Target model ID to migrate to + branch_name (str | Unset): Branch name for the target model + commit_message (str | Unset): Commit message for git sync + delete_views_and_topics_missing_from_source (bool | Unset): When true (default), views and topics in the target + model that are missing from the migrated source are deleted (the source is treated as the complete model). When + false, they are kept (inherited) instead — useful when the source git ref may be missing objects that exist in + omni but not in git, e.g. a newly synced schema. Default: True. + git_ref (str | Unset): Git reference + """ + + target_model_id: UUID + branch_name: str | Unset = UNSET + commit_message: str | Unset = UNSET + delete_views_and_topics_missing_from_source: bool | Unset = True + git_ref: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + target_model_id = str(self.target_model_id) + + branch_name = self.branch_name + + commit_message = self.commit_message + + delete_views_and_topics_missing_from_source = self.delete_views_and_topics_missing_from_source + + git_ref = self.git_ref + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "targetModelId": target_model_id, + } + ) + if branch_name is not UNSET: + field_dict["branchName"] = branch_name + if commit_message is not UNSET: + field_dict["commitMessage"] = commit_message + if delete_views_and_topics_missing_from_source is not UNSET: + field_dict["deleteViewsAndTopicsMissingFromSource"] = delete_views_and_topics_missing_from_source + if git_ref is not UNSET: + field_dict["gitRef"] = git_ref + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + target_model_id = UUID(d.pop("targetModelId")) + + branch_name = d.pop("branchName", UNSET) + + commit_message = d.pop("commitMessage", UNSET) + + delete_views_and_topics_missing_from_source = d.pop("deleteViewsAndTopicsMissingFromSource", UNSET) + + git_ref = d.pop("gitRef", UNSET) + + models_migrate_body = cls( + target_model_id=target_model_id, + branch_name=branch_name, + commit_message=commit_message, + delete_views_and_topics_missing_from_source=delete_views_and_topics_missing_from_source, + git_ref=git_ref, + ) + + models_migrate_body.additional_properties = d + return models_migrate_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_refresh_hard_refresh.py b/omni_python_sdk/models/models_refresh_hard_refresh.py new file mode 100644 index 0000000..51b0fe2 --- /dev/null +++ b/omni_python_sdk/models/models_refresh_hard_refresh.py @@ -0,0 +1,14 @@ +from typing import Literal + +ModelsRefreshHardRefresh = Literal["false", "true"] + +MODELS_REFRESH_HARD_REFRESH_VALUES: set[ModelsRefreshHardRefresh] = { + "false", + "true", +} + + +def check_models_refresh_hard_refresh(value: str) -> ModelsRefreshHardRefresh: + if value in MODELS_REFRESH_HARD_REFRESH_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_REFRESH_HARD_REFRESH_VALUES!r}") diff --git a/omni_python_sdk/models/models_refresh_response.py b/omni_python_sdk/models/models_refresh_response.py new file mode 100644 index 0000000..f6fd61c --- /dev/null +++ b/omni_python_sdk/models/models_refresh_response.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.models_refresh_response_status import ModelsRefreshResponseStatus, check_models_refresh_response_status + +T = TypeVar("T", bound="ModelsRefreshResponse") + + +@_attrs_define +class ModelsRefreshResponse: + """ + Attributes: + job_id (str): Job ID for the refresh operation + model_id (str): Model ID being refreshed + status (ModelsRefreshResponseStatus): Current status of the refresh + """ + + job_id: str + model_id: str + status: ModelsRefreshResponseStatus + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + job_id = self.job_id + + model_id = self.model_id + + status: str = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "jobId": job_id, + "modelId": model_id, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + job_id = d.pop("jobId") + + model_id = d.pop("modelId") + + status = check_models_refresh_response_status(d.pop("status")) + + models_refresh_response = cls( + job_id=job_id, + model_id=model_id, + status=status, + ) + + models_refresh_response.additional_properties = d + return models_refresh_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_refresh_response_status.py b/omni_python_sdk/models/models_refresh_response_status.py new file mode 100644 index 0000000..8872561 --- /dev/null +++ b/omni_python_sdk/models/models_refresh_response_status.py @@ -0,0 +1,15 @@ +from typing import Literal + +ModelsRefreshResponseStatus = Literal["completed", "failed", "running"] + +MODELS_REFRESH_RESPONSE_STATUS_VALUES: set[ModelsRefreshResponseStatus] = { + "completed", + "failed", + "running", +} + + +def check_models_refresh_response_status(value: str) -> ModelsRefreshResponseStatus: + if value in MODELS_REFRESH_RESPONSE_STATUS_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_REFRESH_RESPONSE_STATUS_VALUES!r}") diff --git a/omni_python_sdk/models/models_update_body.py b/omni_python_sdk/models/models_update_body.py new file mode 100644 index 0000000..878a9a3 --- /dev/null +++ b/omni_python_sdk/models/models_update_body.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsUpdateBody") + + +@_attrs_define +class ModelsUpdateBody: + """ + Attributes: + name (str): New name for the model Example: My Renamed Model. + """ + + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + name = d.pop("name") + + models_update_body = cls( + name=name, + ) + + models_update_body.additional_properties = d + return models_update_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_update_field_body.py b/omni_python_sdk/models/models_update_field_body.py new file mode 100644 index 0000000..6af5cbb --- /dev/null +++ b/omni_python_sdk/models/models_update_field_body.py @@ -0,0 +1,302 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.models_update_field_body_filters import ModelsUpdateFieldBodyFilters + from ..models.models_update_field_body_group_filters_item import ModelsUpdateFieldBodyGroupFiltersItem + + +T = TypeVar("T", bound="ModelsUpdateFieldBody") + + +@_attrs_define +class ModelsUpdateFieldBody: + """ + Attributes: + ai_context (str | Unset): AI context for the field + all_values (list[str] | Unset): Deprecated: use sampleValues instead + bin_boundaries (list[float] | Unset): Bin boundaries for binned fields + bin_labels (list[str] | Unset): Labels for bins + description (str | Unset): Field description + drill_fields (list[str] | Unset): Drill-down fields + else_value (str | Unset): Else value for grouped fields + filters (ModelsUpdateFieldBodyFilters | Unset): Filters for the field + format_ (str | Unset): Field format + group_filters (list[ModelsUpdateFieldBodyGroupFiltersItem] | Unset): Group filters + group_label (str | Unset): Group label + group_names (list[str] | Unset): Group names + hidden (bool | Unset): Whether the field is hidden + ignored (bool | Unset): Whether the field is ignored + is_calc (bool | Unset): Whether this is a calculation field + label (str | Unset): Field label + new_field_name (str | Unset): New field name (for rename) + new_view_name (str | Unset): New view name (for move) + sample_values (list[str] | Unset): Sample values for the field + sql (str | Unset): SQL expression for the field + synonyms (list[str] | Unset): Synonyms for the field + tags (list[str] | Unset): Tags for the field + topic_context (str | Unset): Topic context for the field + """ + + ai_context: str | Unset = UNSET + all_values: list[str] | Unset = UNSET + bin_boundaries: list[float] | Unset = UNSET + bin_labels: list[str] | Unset = UNSET + description: str | Unset = UNSET + drill_fields: list[str] | Unset = UNSET + else_value: str | Unset = UNSET + filters: ModelsUpdateFieldBodyFilters | Unset = UNSET + format_: str | Unset = UNSET + group_filters: list[ModelsUpdateFieldBodyGroupFiltersItem] | Unset = UNSET + group_label: str | Unset = UNSET + group_names: list[str] | Unset = UNSET + hidden: bool | Unset = UNSET + ignored: bool | Unset = UNSET + is_calc: bool | Unset = UNSET + label: str | Unset = UNSET + new_field_name: str | Unset = UNSET + new_view_name: str | Unset = UNSET + sample_values: list[str] | Unset = UNSET + sql: str | Unset = UNSET + synonyms: list[str] | Unset = UNSET + tags: list[str] | Unset = UNSET + topic_context: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + ai_context = self.ai_context + + all_values: list[str] | Unset = UNSET + if not isinstance(self.all_values, Unset): + all_values = self.all_values + + bin_boundaries: list[float] | Unset = UNSET + if not isinstance(self.bin_boundaries, Unset): + bin_boundaries = self.bin_boundaries + + bin_labels: list[str] | Unset = UNSET + if not isinstance(self.bin_labels, Unset): + bin_labels = self.bin_labels + + description = self.description + + drill_fields: list[str] | Unset = UNSET + if not isinstance(self.drill_fields, Unset): + drill_fields = self.drill_fields + + else_value = self.else_value + + filters: dict[str, Any] | Unset = UNSET + if not isinstance(self.filters, Unset): + filters = self.filters.to_dict() + + format_ = self.format_ + + group_filters: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.group_filters, Unset): + group_filters = [] + for group_filters_item_data in self.group_filters: + group_filters_item = group_filters_item_data.to_dict() + group_filters.append(group_filters_item) + + group_label = self.group_label + + group_names: list[str] | Unset = UNSET + if not isinstance(self.group_names, Unset): + group_names = self.group_names + + hidden = self.hidden + + ignored = self.ignored + + is_calc = self.is_calc + + label = self.label + + new_field_name = self.new_field_name + + new_view_name = self.new_view_name + + sample_values: list[str] | Unset = UNSET + if not isinstance(self.sample_values, Unset): + sample_values = self.sample_values + + sql = self.sql + + synonyms: list[str] | Unset = UNSET + if not isinstance(self.synonyms, Unset): + synonyms = self.synonyms + + tags: list[str] | Unset = UNSET + if not isinstance(self.tags, Unset): + tags = self.tags + + topic_context = self.topic_context + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if ai_context is not UNSET: + field_dict["aiContext"] = ai_context + if all_values is not UNSET: + field_dict["allValues"] = all_values + if bin_boundaries is not UNSET: + field_dict["binBoundaries"] = bin_boundaries + if bin_labels is not UNSET: + field_dict["binLabels"] = bin_labels + if description is not UNSET: + field_dict["description"] = description + if drill_fields is not UNSET: + field_dict["drillFields"] = drill_fields + if else_value is not UNSET: + field_dict["elseValue"] = else_value + if filters is not UNSET: + field_dict["filters"] = filters + if format_ is not UNSET: + field_dict["format"] = format_ + if group_filters is not UNSET: + field_dict["groupFilters"] = group_filters + if group_label is not UNSET: + field_dict["groupLabel"] = group_label + if group_names is not UNSET: + field_dict["groupNames"] = group_names + if hidden is not UNSET: + field_dict["hidden"] = hidden + if ignored is not UNSET: + field_dict["ignored"] = ignored + if is_calc is not UNSET: + field_dict["isCalc"] = is_calc + if label is not UNSET: + field_dict["label"] = label + if new_field_name is not UNSET: + field_dict["newFieldName"] = new_field_name + if new_view_name is not UNSET: + field_dict["newViewName"] = new_view_name + if sample_values is not UNSET: + field_dict["sampleValues"] = sample_values + if sql is not UNSET: + field_dict["sql"] = sql + if synonyms is not UNSET: + field_dict["synonyms"] = synonyms + if tags is not UNSET: + field_dict["tags"] = tags + if topic_context is not UNSET: + field_dict["topicContext"] = topic_context + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_update_field_body_filters import ModelsUpdateFieldBodyFilters + from ..models.models_update_field_body_group_filters_item import ModelsUpdateFieldBodyGroupFiltersItem + + d = dict(src_dict) + ai_context = d.pop("aiContext", UNSET) + + all_values = cast(list[str], d.pop("allValues", UNSET)) + + bin_boundaries = cast(list[float], d.pop("binBoundaries", UNSET)) + + bin_labels = cast(list[str], d.pop("binLabels", UNSET)) + + description = d.pop("description", UNSET) + + drill_fields = cast(list[str], d.pop("drillFields", UNSET)) + + else_value = d.pop("elseValue", UNSET) + + _filters = d.pop("filters", UNSET) + filters: ModelsUpdateFieldBodyFilters | Unset + if isinstance(_filters, Unset): + filters = UNSET + else: + filters = ModelsUpdateFieldBodyFilters.from_dict(_filters) + + format_ = d.pop("format", UNSET) + + _group_filters = d.pop("groupFilters", UNSET) + group_filters: list[ModelsUpdateFieldBodyGroupFiltersItem] | Unset = UNSET + if _group_filters is not UNSET: + group_filters = [] + for group_filters_item_data in _group_filters: + group_filters_item = ModelsUpdateFieldBodyGroupFiltersItem.from_dict(group_filters_item_data) + + group_filters.append(group_filters_item) + + group_label = d.pop("groupLabel", UNSET) + + group_names = cast(list[str], d.pop("groupNames", UNSET)) + + hidden = d.pop("hidden", UNSET) + + ignored = d.pop("ignored", UNSET) + + is_calc = d.pop("isCalc", UNSET) + + label = d.pop("label", UNSET) + + new_field_name = d.pop("newFieldName", UNSET) + + new_view_name = d.pop("newViewName", UNSET) + + sample_values = cast(list[str], d.pop("sampleValues", UNSET)) + + sql = d.pop("sql", UNSET) + + synonyms = cast(list[str], d.pop("synonyms", UNSET)) + + tags = cast(list[str], d.pop("tags", UNSET)) + + topic_context = d.pop("topicContext", UNSET) + + models_update_field_body = cls( + ai_context=ai_context, + all_values=all_values, + bin_boundaries=bin_boundaries, + bin_labels=bin_labels, + description=description, + drill_fields=drill_fields, + else_value=else_value, + filters=filters, + format_=format_, + group_filters=group_filters, + group_label=group_label, + group_names=group_names, + hidden=hidden, + ignored=ignored, + is_calc=is_calc, + label=label, + new_field_name=new_field_name, + new_view_name=new_view_name, + sample_values=sample_values, + sql=sql, + synonyms=synonyms, + tags=tags, + topic_context=topic_context, + ) + + models_update_field_body.additional_properties = d + return models_update_field_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_update_field_body_filters.py b/omni_python_sdk/models/models_update_field_body_filters.py new file mode 100644 index 0000000..276ac63 --- /dev/null +++ b/omni_python_sdk/models/models_update_field_body_filters.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsUpdateFieldBodyFilters") + + +@_attrs_define +class ModelsUpdateFieldBodyFilters: + """Filters for the field""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + models_update_field_body_filters = cls() + + models_update_field_body_filters.additional_properties = d + return models_update_field_body_filters + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_update_field_body_group_filters_item.py b/omni_python_sdk/models/models_update_field_body_group_filters_item.py new file mode 100644 index 0000000..f63cad6 --- /dev/null +++ b/omni_python_sdk/models/models_update_field_body_group_filters_item.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsUpdateFieldBodyGroupFiltersItem") + + +@_attrs_define +class ModelsUpdateFieldBodyGroupFiltersItem: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + models_update_field_body_group_filters_item = cls() + + models_update_field_body_group_filters_item.additional_properties = d + return models_update_field_body_group_filters_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_update_response.py b/omni_python_sdk/models/models_update_response.py new file mode 100644 index 0000000..beafb9b --- /dev/null +++ b/omni_python_sdk/models/models_update_response.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.models_update_response_model import ModelsUpdateResponseModel + + +T = TypeVar("T", bound="ModelsUpdateResponse") + + +@_attrs_define +class ModelsUpdateResponse: + """ + Attributes: + model (ModelsUpdateResponseModel): Updated model details + success (bool): Whether the operation succeeded + """ + + model: ModelsUpdateResponseModel + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + model = self.model.to_dict() + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "model": model, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_update_response_model import ModelsUpdateResponseModel + + d = dict(src_dict) + model = ModelsUpdateResponseModel.from_dict(d.pop("model")) + + success = d.pop("success") + + models_update_response = cls( + model=model, + success=success, + ) + + models_update_response.additional_properties = d + return models_update_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_update_response_model.py b/omni_python_sdk/models/models_update_response_model.py new file mode 100644 index 0000000..d1ce02e --- /dev/null +++ b/omni_python_sdk/models/models_update_response_model.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ModelsUpdateResponseModel") + + +@_attrs_define +class ModelsUpdateResponseModel: + """Updated model details + + Attributes: + id (UUID): Model ID + name (str): Updated model name + """ + + id: UUID + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = UUID(d.pop("id")) + + name = d.pop("name") + + models_update_response_model = cls( + id=id, + name=name, + ) + + models_update_response_model.additional_properties = d + return models_update_response_model + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_update_topic_body.py b/omni_python_sdk/models/models_update_topic_body.py new file mode 100644 index 0000000..e81bd63 --- /dev/null +++ b/omni_python_sdk/models/models_update_topic_body.py @@ -0,0 +1,97 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsUpdateTopicBody") + + +@_attrs_define +class ModelsUpdateTopicBody: + """ + Attributes: + description (str | Unset): Topic description + group_label (str | Unset): Group label for the topic + hidden (bool | Unset): Whether the topic is hidden + label (str | Unset): Topic label + new_topic_name (str | Unset): New topic name (for rename) + """ + + description: str | Unset = UNSET + group_label: str | Unset = UNSET + hidden: bool | Unset = UNSET + label: str | Unset = UNSET + new_topic_name: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + description = self.description + + group_label = self.group_label + + hidden = self.hidden + + label = self.label + + new_topic_name = self.new_topic_name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if description is not UNSET: + field_dict["description"] = description + if group_label is not UNSET: + field_dict["groupLabel"] = group_label + if hidden is not UNSET: + field_dict["hidden"] = hidden + if label is not UNSET: + field_dict["label"] = label + if new_topic_name is not UNSET: + field_dict["newTopicName"] = new_topic_name + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + description = d.pop("description", UNSET) + + group_label = d.pop("groupLabel", UNSET) + + hidden = d.pop("hidden", UNSET) + + label = d.pop("label", UNSET) + + new_topic_name = d.pop("newTopicName", UNSET) + + models_update_topic_body = cls( + description=description, + group_label=group_label, + hidden=hidden, + label=label, + new_topic_name=new_topic_name, + ) + + models_update_topic_body.additional_properties = d + return models_update_topic_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_update_view_body.py b/omni_python_sdk/models/models_update_view_body.py new file mode 100644 index 0000000..ebc8184 --- /dev/null +++ b/omni_python_sdk/models/models_update_view_body.py @@ -0,0 +1,108 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsUpdateViewBody") + + +@_attrs_define +class ModelsUpdateViewBody: + """ + Attributes: + ai_context (str | Unset): AI context for the view + description (str | Unset): View description + format_ (str | Unset): View format + hidden (bool | Unset): Whether the view is hidden + label (str | Unset): View label + tags (list[str] | Unset): Tags for the view + """ + + ai_context: str | Unset = UNSET + description: str | Unset = UNSET + format_: str | Unset = UNSET + hidden: bool | Unset = UNSET + label: str | Unset = UNSET + tags: list[str] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + ai_context = self.ai_context + + description = self.description + + format_ = self.format_ + + hidden = self.hidden + + label = self.label + + tags: list[str] | Unset = UNSET + if not isinstance(self.tags, Unset): + tags = self.tags + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if ai_context is not UNSET: + field_dict["aiContext"] = ai_context + if description is not UNSET: + field_dict["description"] = description + if format_ is not UNSET: + field_dict["format"] = format_ + if hidden is not UNSET: + field_dict["hidden"] = hidden + if label is not UNSET: + field_dict["label"] = label + if tags is not UNSET: + field_dict["tags"] = tags + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + ai_context = d.pop("aiContext", UNSET) + + description = d.pop("description", UNSET) + + format_ = d.pop("format", UNSET) + + hidden = d.pop("hidden", UNSET) + + label = d.pop("label", UNSET) + + tags = cast(list[str], d.pop("tags", UNSET)) + + models_update_view_body = cls( + ai_context=ai_context, + description=description, + format_=format_, + hidden=hidden, + label=label, + tags=tags, + ) + + models_update_view_body.additional_properties = d + return models_update_view_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_validate_response.py b/omni_python_sdk/models/models_validate_response.py new file mode 100644 index 0000000..85a5bf4 --- /dev/null +++ b/omni_python_sdk/models/models_validate_response.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.models_validate_response_issues_item import ModelsValidateResponseIssuesItem + + +T = TypeVar("T", bound="ModelsValidateResponse") + + +@_attrs_define +class ModelsValidateResponse: + """ + Attributes: + issues (list[ModelsValidateResponseIssuesItem]): List of validation issues + valid (bool): Whether the model is valid + """ + + issues: list[ModelsValidateResponseIssuesItem] + valid: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + issues = [] + for issues_item_data in self.issues: + issues_item = issues_item_data.to_dict() + issues.append(issues_item) + + valid = self.valid + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "issues": issues, + "valid": valid, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.models_validate_response_issues_item import ModelsValidateResponseIssuesItem + + d = dict(src_dict) + issues = [] + _issues = d.pop("issues") + for issues_item_data in _issues: + issues_item = ModelsValidateResponseIssuesItem.from_dict(issues_item_data) + + issues.append(issues_item) + + valid = d.pop("valid") + + models_validate_response = cls( + issues=issues, + valid=valid, + ) + + models_validate_response.additional_properties = d + return models_validate_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_validate_response_issues_item.py b/omni_python_sdk/models/models_validate_response_issues_item.py new file mode 100644 index 0000000..65b4fb4 --- /dev/null +++ b/omni_python_sdk/models/models_validate_response_issues_item.py @@ -0,0 +1,93 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.models_validate_response_issues_item_severity import ( + ModelsValidateResponseIssuesItemSeverity, + check_models_validate_response_issues_item_severity, +) +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ModelsValidateResponseIssuesItem") + + +@_attrs_define +class ModelsValidateResponseIssuesItem: + """ + Attributes: + message (str): Validation issue message + severity (ModelsValidateResponseIssuesItemSeverity): Issue severity + field (str | Unset): Field name with the issue + view (str | Unset): View name with the issue + """ + + message: str + severity: ModelsValidateResponseIssuesItemSeverity + field: str | Unset = UNSET + view: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + severity: str = self.severity + + field = self.field + + view = self.view + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + "severity": severity, + } + ) + if field is not UNSET: + field_dict["field"] = field + if view is not UNSET: + field_dict["view"] = view + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + severity = check_models_validate_response_issues_item_severity(d.pop("severity")) + + field = d.pop("field", UNSET) + + view = d.pop("view", UNSET) + + models_validate_response_issues_item = cls( + message=message, + severity=severity, + field=field, + view=view, + ) + + models_validate_response_issues_item.additional_properties = d + return models_validate_response_issues_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/models_validate_response_issues_item_severity.py b/omni_python_sdk/models/models_validate_response_issues_item_severity.py new file mode 100644 index 0000000..c5207f1 --- /dev/null +++ b/omni_python_sdk/models/models_validate_response_issues_item_severity.py @@ -0,0 +1,16 @@ +from typing import Literal + +ModelsValidateResponseIssuesItemSeverity = Literal["error", "warning"] + +MODELS_VALIDATE_RESPONSE_ISSUES_ITEM_SEVERITY_VALUES: set[ModelsValidateResponseIssuesItemSeverity] = { + "error", + "warning", +} + + +def check_models_validate_response_issues_item_severity(value: str) -> ModelsValidateResponseIssuesItemSeverity: + if value in MODELS_VALIDATE_RESPONSE_ISSUES_ITEM_SEVERITY_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {MODELS_VALIDATE_RESPONSE_ISSUES_ITEM_SEVERITY_VALUES!r}" + ) diff --git a/omni_python_sdk/models/models_yaml_delete_mode.py b/omni_python_sdk/models/models_yaml_delete_mode.py new file mode 100644 index 0000000..628feff --- /dev/null +++ b/omni_python_sdk/models/models_yaml_delete_mode.py @@ -0,0 +1,17 @@ +from typing import Literal + +ModelsYamlDeleteMode = Literal["combined", "extension", "fully-resolved", "merged", "staged"] + +MODELS_YAML_DELETE_MODE_VALUES: set[ModelsYamlDeleteMode] = { + "combined", + "extension", + "fully-resolved", + "merged", + "staged", +} + + +def check_models_yaml_delete_mode(value: str) -> ModelsYamlDeleteMode: + if value in MODELS_YAML_DELETE_MODE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_YAML_DELETE_MODE_VALUES!r}") diff --git a/omni_python_sdk/models/models_yaml_get_mode.py b/omni_python_sdk/models/models_yaml_get_mode.py new file mode 100644 index 0000000..636ae29 --- /dev/null +++ b/omni_python_sdk/models/models_yaml_get_mode.py @@ -0,0 +1,17 @@ +from typing import Literal + +ModelsYamlGetMode = Literal["combined", "extension", "fully-resolved", "merged", "staged"] + +MODELS_YAML_GET_MODE_VALUES: set[ModelsYamlGetMode] = { + "combined", + "extension", + "fully-resolved", + "merged", + "staged", +} + + +def check_models_yaml_get_mode(value: str) -> ModelsYamlGetMode: + if value in MODELS_YAML_GET_MODE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {MODELS_YAML_GET_MODE_VALUES!r}") diff --git a/omni_python_sdk/models/owner_internal.py b/omni_python_sdk/models/owner_internal.py new file mode 100644 index 0000000..e7f1ef9 --- /dev/null +++ b/omni_python_sdk/models/owner_internal.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="OwnerInternal") + + +@_attrs_define +class OwnerInternal: + """Content owner + + Attributes: + id (str): Owner membership ID + name (str): Owner display name + """ + + id: str + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + name = d.pop("name") + + owner_internal = cls( + id=id, + name=name, + ) + + owner_internal.additional_properties = d + return owner_internal + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/page_container.py b/omni_python_sdk/models/page_container.py new file mode 100644 index 0000000..caf4e22 --- /dev/null +++ b/omni_python_sdk/models/page_container.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PageContainer") + + +@_attrs_define +class PageContainer: + """Page container — a top-level page wrapping a single grid, stack, or reference container, optionally per + breakpoint/media. (Not statically modeled; use plain dicts.) + + """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + page_container = cls() + + page_container.additional_properties = d + return page_container + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/page_info.py b/omni_python_sdk/models/page_info.py new file mode 100644 index 0000000..aa0113c --- /dev/null +++ b/omni_python_sdk/models/page_info.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="PageInfo") + + +@_attrs_define +class PageInfo: + """ + Attributes: + has_next_page (bool): Whether more results are available + next_cursor (None | str): Cursor for fetching the next page + page_size (float): Number of results per page + total_records (float): Total number of records matching the query + """ + + has_next_page: bool + next_cursor: None | str + page_size: float + total_records: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + has_next_page = self.has_next_page + + next_cursor: None | str + next_cursor = self.next_cursor + + page_size = self.page_size + + total_records = self.total_records + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "hasNextPage": has_next_page, + "nextCursor": next_cursor, + "pageSize": page_size, + "totalRecords": total_records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + has_next_page = d.pop("hasNextPage") + + def _parse_next_cursor(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + next_cursor = _parse_next_cursor(d.pop("nextCursor")) + + page_size = d.pop("pageSize") + + total_records = d.pop("totalRecords") + + page_info = cls( + has_next_page=has_next_page, + next_cursor=next_cursor, + page_size=page_size, + total_records=total_records, + ) + + page_info.additional_properties = d + return page_info + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_presentation_patch_external.py b/omni_python_sdk/models/query_presentation_patch_external.py new file mode 100644 index 0000000..a4d7eac --- /dev/null +++ b/omni_python_sdk/models/query_presentation_patch_external.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="QueryPresentationPatchExternal") + + +@_attrs_define +class QueryPresentationPatchExternal: + """(Not statically modeled; use plain dicts.)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + query_presentation_patch_external = cls() + + query_presentation_patch_external.additional_properties = d + return query_presentation_patch_external + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_presentation_read_external.py b/omni_python_sdk/models/query_presentation_read_external.py new file mode 100644 index 0000000..8ee516b --- /dev/null +++ b/omni_python_sdk/models/query_presentation_read_external.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="QueryPresentationReadExternal") + + +@_attrs_define +class QueryPresentationReadExternal: + """(Not statically modeled; use plain dicts.)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + query_presentation_read_external = cls() + + query_presentation_read_external.additional_properties = d + return query_presentation_read_external + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_presentations_patch_external.py b/omni_python_sdk/models/query_presentations_patch_external.py new file mode 100644 index 0000000..36d6b66 --- /dev/null +++ b/omni_python_sdk/models/query_presentations_patch_external.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="QueryPresentationsPatchExternal") + + +@_attrs_define +class QueryPresentationsPatchExternal: + """(Not statically modeled; use plain dicts.)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + query_presentations_patch_external = cls() + + query_presentations_patch_external.additional_properties = d + return query_presentations_patch_external + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_presentations_read_external.py b/omni_python_sdk/models/query_presentations_read_external.py new file mode 100644 index 0000000..4e90716 --- /dev/null +++ b/omni_python_sdk/models/query_presentations_read_external.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="QueryPresentationsReadExternal") + + +@_attrs_define +class QueryPresentationsReadExternal: + """(Not statically modeled; use plain dicts.)""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + query_presentations_read_external = cls() + + query_presentations_read_external.additional_properties = d + return query_presentations_read_external + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_run_body.py b/omni_python_sdk/models/query_run_body.py new file mode 100644 index 0000000..41fdc8a --- /dev/null +++ b/omni_python_sdk/models/query_run_body.py @@ -0,0 +1,174 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.query_run_body_cache import QueryRunBodyCache, check_query_run_body_cache +from ..models.query_run_body_result_type import QueryRunBodyResultType, check_query_run_body_result_type +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryRunBody") + + +@_attrs_define +class QueryRunBody: + """ + Attributes: + branch_id (UUID | Unset): Optional model branch to run the query against. Must belong to the same shared model + as the query. When omitted, the query runs against the shared model. Takes precedence over the legacy + `?branch_id=` URL query parameter. Example: 550e8400-e29b-41d4-a716-446655440000. + cache (QueryRunBodyCache | Unset): Cache policy for query execution. Controls whether to use cached results. + Example: normal. + environment_connection_id (UUID | Unset): Connection ID of the environment to run the query against, overriding + the connection environment inherited from the (target) user's session or default. Must be a configured + environment of the query model's connection that the user can access. Example: + 550e8400-e29b-41d4-a716-446655440000. + format_results (bool | Unset): Whether to format result values (e.g., apply number formatting). Only valid when + resultType is specified. + plan_only (bool | Unset): If true, returns only the query execution plan without running the query. Default: + False. + query (Any | Unset): The semantic query definition including fields, filters, sorts, and other query parameters. + result_type (QueryRunBodyResultType | Unset): Output format for the results. If not specified, returns + base64-encoded Arrow format. + user_id (UUID | Unset): Alternate location for the `?userId=` query parameter. Prefer the query parameter — this + body field exists for backwards compatibility. Supplying both forms results in a 400. Only valid for org-scoped + API keys; when set, the user's attributes are applied for row-level security and connection-environment + switching. Example: 550e8400-e29b-41d4-a716-446655440000. + """ + + branch_id: UUID | Unset = UNSET + cache: QueryRunBodyCache | Unset = UNSET + environment_connection_id: UUID | Unset = UNSET + format_results: bool | Unset = UNSET + plan_only: bool | Unset = False + query: Any | Unset = UNSET + result_type: QueryRunBodyResultType | Unset = UNSET + user_id: UUID | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + cache: str | Unset = UNSET + if not isinstance(self.cache, Unset): + cache = self.cache + + environment_connection_id: str | Unset = UNSET + if not isinstance(self.environment_connection_id, Unset): + environment_connection_id = str(self.environment_connection_id) + + format_results = self.format_results + + plan_only = self.plan_only + + query = self.query + + result_type: str | Unset = UNSET + if not isinstance(self.result_type, Unset): + result_type = self.result_type + + user_id: str | Unset = UNSET + if not isinstance(self.user_id, Unset): + user_id = str(self.user_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if branch_id is not UNSET: + field_dict["branchId"] = branch_id + if cache is not UNSET: + field_dict["cache"] = cache + if environment_connection_id is not UNSET: + field_dict["environmentConnectionId"] = environment_connection_id + if format_results is not UNSET: + field_dict["formatResults"] = format_results + if plan_only is not UNSET: + field_dict["planOnly"] = plan_only + if query is not UNSET: + field_dict["query"] = query + if result_type is not UNSET: + field_dict["resultType"] = result_type + if user_id is not UNSET: + field_dict["userId"] = user_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + _branch_id = d.pop("branchId", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + _cache = d.pop("cache", UNSET) + cache: QueryRunBodyCache | Unset + if isinstance(_cache, Unset): + cache = UNSET + else: + cache = check_query_run_body_cache(_cache) + + _environment_connection_id = d.pop("environmentConnectionId", UNSET) + environment_connection_id: UUID | Unset + if isinstance(_environment_connection_id, Unset): + environment_connection_id = UNSET + else: + environment_connection_id = UUID(_environment_connection_id) + + format_results = d.pop("formatResults", UNSET) + + plan_only = d.pop("planOnly", UNSET) + + query = d.pop("query", UNSET) + + _result_type = d.pop("resultType", UNSET) + result_type: QueryRunBodyResultType | Unset + if isinstance(_result_type, Unset): + result_type = UNSET + else: + result_type = check_query_run_body_result_type(_result_type) + + _user_id = d.pop("userId", UNSET) + user_id: UUID | Unset + if isinstance(_user_id, Unset): + user_id = UNSET + else: + user_id = UUID(_user_id) + + query_run_body = cls( + branch_id=branch_id, + cache=cache, + environment_connection_id=environment_connection_id, + format_results=format_results, + plan_only=plan_only, + query=query, + result_type=result_type, + user_id=user_id, + ) + + query_run_body.additional_properties = d + return query_run_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_run_body_cache.py b/omni_python_sdk/models/query_run_body_cache.py new file mode 100644 index 0000000..737dd3d --- /dev/null +++ b/omni_python_sdk/models/query_run_body_cache.py @@ -0,0 +1,16 @@ +from typing import Literal + +QueryRunBodyCache = Literal["disabled", "normal", "refresh", "refresh_all"] + +QUERY_RUN_BODY_CACHE_VALUES: set[QueryRunBodyCache] = { + "disabled", + "normal", + "refresh", + "refresh_all", +} + + +def check_query_run_body_cache(value: str) -> QueryRunBodyCache: + if value in QUERY_RUN_BODY_CACHE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {QUERY_RUN_BODY_CACHE_VALUES!r}") diff --git a/omni_python_sdk/models/query_run_body_result_type.py b/omni_python_sdk/models/query_run_body_result_type.py new file mode 100644 index 0000000..db1af54 --- /dev/null +++ b/omni_python_sdk/models/query_run_body_result_type.py @@ -0,0 +1,15 @@ +from typing import Literal + +QueryRunBodyResultType = Literal["csv", "json", "xlsx"] + +QUERY_RUN_BODY_RESULT_TYPE_VALUES: set[QueryRunBodyResultType] = { + "csv", + "json", + "xlsx", +} + + +def check_query_run_body_result_type(value: str) -> QueryRunBodyResultType: + if value in QUERY_RUN_BODY_RESULT_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {QUERY_RUN_BODY_RESULT_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/query_run_response.py b/omni_python_sdk/models/query_run_response.py new file mode 100644 index 0000000..94ec633 --- /dev/null +++ b/omni_python_sdk/models/query_run_response.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryRunResponse") + + +@_attrs_define +class QueryRunResponse: + """ + Attributes: + completed_queries (list[Any] | Unset): Queries that completed synchronously with their results. + job_ids (list[str] | Unset): Job IDs for queries running asynchronously. Use /api/v1/query/wait to poll for + results. Example: ['job_abc123', 'job_def456']. + plan (Any | Unset): Query execution plan (only present if planOnly is true). + """ + + completed_queries: list[Any] | Unset = UNSET + job_ids: list[str] | Unset = UNSET + plan: Any | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + completed_queries: list[Any] | Unset = UNSET + if not isinstance(self.completed_queries, Unset): + completed_queries = self.completed_queries + + job_ids: list[str] | Unset = UNSET + if not isinstance(self.job_ids, Unset): + job_ids = self.job_ids + + plan = self.plan + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if completed_queries is not UNSET: + field_dict["completedQueries"] = completed_queries + if job_ids is not UNSET: + field_dict["jobIds"] = job_ids + if plan is not UNSET: + field_dict["plan"] = plan + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + completed_queries = cast(list[Any], d.pop("completedQueries", UNSET)) + + job_ids = cast(list[str], d.pop("jobIds", UNSET)) + + plan = d.pop("plan", UNSET) + + query_run_response = cls( + completed_queries=completed_queries, + job_ids=job_ids, + plan=plan, + ) + + query_run_response.additional_properties = d + return query_run_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_timeout_response.py b/omni_python_sdk/models/query_timeout_response.py new file mode 100644 index 0000000..322eafa --- /dev/null +++ b/omni_python_sdk/models/query_timeout_response.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="QueryTimeoutResponse") + + +@_attrs_define +class QueryTimeoutResponse: + """ + Attributes: + detail (str): Error message indicating the query timed out. Example: Query timed out. + timed_out (bool): Always true for timeout responses. Example: True. + remaining_job_ids (list[str] | Unset): Job IDs for queries that have not yet completed. Use /api/v1/query/wait + to poll for results. + """ + + detail: str + timed_out: bool + remaining_job_ids: list[str] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + timed_out = self.timed_out + + remaining_job_ids: list[str] | Unset = UNSET + if not isinstance(self.remaining_job_ids, Unset): + remaining_job_ids = self.remaining_job_ids + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "timed_out": timed_out, + } + ) + if remaining_job_ids is not UNSET: + field_dict["remaining_job_ids"] = remaining_job_ids + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + timed_out = d.pop("timed_out") + + remaining_job_ids = cast(list[str], d.pop("remaining_job_ids", UNSET)) + + query_timeout_response = cls( + detail=detail, + timed_out=timed_out, + remaining_job_ids=remaining_job_ids, + ) + + query_timeout_response.additional_properties = d + return query_timeout_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_wait_response.py b/omni_python_sdk/models/query_wait_response.py new file mode 100644 index 0000000..2496192 --- /dev/null +++ b/omni_python_sdk/models/query_wait_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="QueryWaitResponse") + + +@_attrs_define +class QueryWaitResponse: + """ + Attributes: + results (list[Any]): Array of completed query results. Each result contains the query data or an error. + """ + + results: list[Any] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + results = self.results + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "results": results, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + results = cast(list[Any], d.pop("results")) + + query_wait_response = cls( + results=results, + ) + + query_wait_response.additional_properties = d + return query_wait_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/reference_container.py b/omni_python_sdk/models/reference_container.py new file mode 100644 index 0000000..41c55bc --- /dev/null +++ b/omni_python_sdk/models/reference_container.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ReferenceContainer") + + +@_attrs_define +class ReferenceContainer: + """Reference container — points at another container in the collection by its instanceKey. (Not statically modeled; use + plain dicts.) + + """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + reference_container = cls() + + reference_container.additional_properties = d + return reference_container + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/role_assignment_result.py b/omni_python_sdk/models/role_assignment_result.py new file mode 100644 index 0000000..c0bf884 --- /dev/null +++ b/omni_python_sdk/models/role_assignment_result.py @@ -0,0 +1,165 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.role_origin_type_0 import RoleOriginType0 + from ..models.role_origin_type_1 import RoleOriginType1 + from ..models.role_origin_type_2 import RoleOriginType2 + from ..models.role_origin_type_3 import RoleOriginType3 + + +T = TypeVar("T", bound="RoleAssignmentResult") + + +@_attrs_define +class RoleAssignmentResult: + """ + Attributes: + base_role (str): The base role definition name Example: VIEWER. + connection_id (UUID): Connection this role applies to + from_ (RoleOriginType0 | RoleOriginType1 | RoleOriginType2 | RoleOriginType3): Origin of this role assignment + model_id (UUID): Model this role applies to + priority (float): Priority for role resolution (higher = more permissive) + resolved (bool): Whether this is the resolved (effective) role + role_name (str): The role name (base or custom) Example: VIEWER. + """ + + base_role: str + connection_id: UUID + from_: RoleOriginType0 | RoleOriginType1 | RoleOriginType2 | RoleOriginType3 + model_id: UUID + priority: float + resolved: bool + role_name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.role_origin_type_0 import RoleOriginType0 + from ..models.role_origin_type_1 import RoleOriginType1 + from ..models.role_origin_type_2 import RoleOriginType2 + + base_role = self.base_role + + connection_id = str(self.connection_id) + + from_: dict[str, Any] + if isinstance(self.from_, RoleOriginType0): + from_ = self.from_.to_dict() + elif isinstance(self.from_, RoleOriginType1): + from_ = self.from_.to_dict() + elif isinstance(self.from_, RoleOriginType2): + from_ = self.from_.to_dict() + else: + from_ = self.from_.to_dict() + + model_id = str(self.model_id) + + priority = self.priority + + resolved = self.resolved + + role_name = self.role_name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "baseRole": base_role, + "connectionId": connection_id, + "from": from_, + "modelId": model_id, + "priority": priority, + "resolved": resolved, + "roleName": role_name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.role_origin_type_0 import RoleOriginType0 + from ..models.role_origin_type_1 import RoleOriginType1 + from ..models.role_origin_type_2 import RoleOriginType2 + from ..models.role_origin_type_3 import RoleOriginType3 + + d = dict(src_dict) + base_role = d.pop("baseRole") + + connection_id = UUID(d.pop("connectionId")) + + def _parse_from_(data: object) -> RoleOriginType0 | RoleOriginType1 | RoleOriginType2 | RoleOriginType3: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_role_origin_type_0 = RoleOriginType0.from_dict(data) + + return componentsschemas_role_origin_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_role_origin_type_1 = RoleOriginType1.from_dict(data) + + return componentsschemas_role_origin_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_role_origin_type_2 = RoleOriginType2.from_dict(data) + + return componentsschemas_role_origin_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_role_origin_type_3 = RoleOriginType3.from_dict(data) + + return componentsschemas_role_origin_type_3 + + from_ = _parse_from_(d.pop("from")) + + model_id = UUID(d.pop("modelId")) + + priority = d.pop("priority") + + resolved = d.pop("resolved") + + role_name = d.pop("roleName") + + role_assignment_result = cls( + base_role=base_role, + connection_id=connection_id, + from_=from_, + model_id=model_id, + priority=priority, + resolved=resolved, + role_name=role_name, + ) + + role_assignment_result.additional_properties = d + return role_assignment_result + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/role_origin_type_0.py b/omni_python_sdk/models/role_origin_type_0.py new file mode 100644 index 0000000..c6a60f7 --- /dev/null +++ b/omni_python_sdk/models/role_origin_type_0.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.role_origin_type_0_type import RoleOriginType0Type, check_role_origin_type_0_type + +T = TypeVar("T", bound="RoleOriginType0") + + +@_attrs_define +class RoleOriginType0: + """ + Attributes: + type_ (RoleOriginType0Type): Role assigned directly to user + """ + + type_: RoleOriginType0Type + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_: str = self.type_ + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + type_ = check_role_origin_type_0_type(d.pop("type")) + + role_origin_type_0 = cls( + type_=type_, + ) + + role_origin_type_0.additional_properties = d + return role_origin_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/role_origin_type_0_type.py b/omni_python_sdk/models/role_origin_type_0_type.py new file mode 100644 index 0000000..eee4557 --- /dev/null +++ b/omni_python_sdk/models/role_origin_type_0_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +RoleOriginType0Type = Literal["USER"] + +ROLE_ORIGIN_TYPE_0_TYPE_VALUES: set[RoleOriginType0Type] = { + "USER", +} + + +def check_role_origin_type_0_type(value: str) -> RoleOriginType0Type: + if value in ROLE_ORIGIN_TYPE_0_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {ROLE_ORIGIN_TYPE_0_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/role_origin_type_1.py b/omni_python_sdk/models/role_origin_type_1.py new file mode 100644 index 0000000..7d13fda --- /dev/null +++ b/omni_python_sdk/models/role_origin_type_1.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.role_origin_type_1_type import RoleOriginType1Type, check_role_origin_type_1_type + +T = TypeVar("T", bound="RoleOriginType1") + + +@_attrs_define +class RoleOriginType1: + """ + Attributes: + type_ (RoleOriginType1Type): Role inherited from organization + """ + + type_: RoleOriginType1Type + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_: str = self.type_ + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + type_ = check_role_origin_type_1_type(d.pop("type")) + + role_origin_type_1 = cls( + type_=type_, + ) + + role_origin_type_1.additional_properties = d + return role_origin_type_1 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/role_origin_type_1_type.py b/omni_python_sdk/models/role_origin_type_1_type.py new file mode 100644 index 0000000..b09df67 --- /dev/null +++ b/omni_python_sdk/models/role_origin_type_1_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +RoleOriginType1Type = Literal["ORG"] + +ROLE_ORIGIN_TYPE_1_TYPE_VALUES: set[RoleOriginType1Type] = { + "ORG", +} + + +def check_role_origin_type_1_type(value: str) -> RoleOriginType1Type: + if value in ROLE_ORIGIN_TYPE_1_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {ROLE_ORIGIN_TYPE_1_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/role_origin_type_2.py b/omni_python_sdk/models/role_origin_type_2.py new file mode 100644 index 0000000..c1504ac --- /dev/null +++ b/omni_python_sdk/models/role_origin_type_2.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.role_origin_type_2_type import RoleOriginType2Type, check_role_origin_type_2_type + +T = TypeVar("T", bound="RoleOriginType2") + + +@_attrs_define +class RoleOriginType2: + """ + Attributes: + type_ (RoleOriginType2Type): Connection base role + """ + + type_: RoleOriginType2Type + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_: str = self.type_ + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + type_ = check_role_origin_type_2_type(d.pop("type")) + + role_origin_type_2 = cls( + type_=type_, + ) + + role_origin_type_2.additional_properties = d + return role_origin_type_2 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/role_origin_type_2_type.py b/omni_python_sdk/models/role_origin_type_2_type.py new file mode 100644 index 0000000..3b13a1d --- /dev/null +++ b/omni_python_sdk/models/role_origin_type_2_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +RoleOriginType2Type = Literal["BASE"] + +ROLE_ORIGIN_TYPE_2_TYPE_VALUES: set[RoleOriginType2Type] = { + "BASE", +} + + +def check_role_origin_type_2_type(value: str) -> RoleOriginType2Type: + if value in ROLE_ORIGIN_TYPE_2_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {ROLE_ORIGIN_TYPE_2_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/role_origin_type_3.py b/omni_python_sdk/models/role_origin_type_3.py new file mode 100644 index 0000000..07c6a1d --- /dev/null +++ b/omni_python_sdk/models/role_origin_type_3.py @@ -0,0 +1,87 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.role_origin_type_3_type import RoleOriginType3Type, check_role_origin_type_3_type + +T = TypeVar("T", bound="RoleOriginType3") + + +@_attrs_define +class RoleOriginType3: + """ + Attributes: + depth (float): Nesting depth of the group + mini_uuid (str): Short identifier of the group Example: abc123. + name (str): Name of the group Example: Engineering Team. + type_ (RoleOriginType3Type): Role inherited from group membership + """ + + depth: float + mini_uuid: str + name: str + type_: RoleOriginType3Type + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + depth = self.depth + + mini_uuid = self.mini_uuid + + name = self.name + + type_: str = self.type_ + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "depth": depth, + "miniUuid": mini_uuid, + "name": name, + "type": type_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + depth = d.pop("depth") + + mini_uuid = d.pop("miniUuid") + + name = d.pop("name") + + type_ = check_role_origin_type_3_type(d.pop("type")) + + role_origin_type_3 = cls( + depth=depth, + mini_uuid=mini_uuid, + name=name, + type_=type_, + ) + + role_origin_type_3.additional_properties = d + return role_origin_type_3 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/role_origin_type_3_type.py b/omni_python_sdk/models/role_origin_type_3_type.py new file mode 100644 index 0000000..28e528c --- /dev/null +++ b/omni_python_sdk/models/role_origin_type_3_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +RoleOriginType3Type = Literal["GROUP"] + +ROLE_ORIGIN_TYPE_3_TYPE_VALUES: set[RoleOriginType3Type] = { + "GROUP", +} + + +def check_role_origin_type_3_type(value: str) -> RoleOriginType3Type: + if value in ROLE_ORIGIN_TYPE_3_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {ROLE_ORIGIN_TYPE_3_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/routine_create_body.py b/omni_python_sdk/models/routine_create_body.py new file mode 100644 index 0000000..62e0e84 --- /dev/null +++ b/omni_python_sdk/models/routine_create_body.py @@ -0,0 +1,159 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.routine_email_destination import RoutineEmailDestination + from ..models.routine_slack_destination import RoutineSlackDestination + + +T = TypeVar("T", bound="RoutineCreateBody") + + +@_attrs_define +class RoutineCreateBody: + """ + Attributes: + model_id (UUID): The UUID of the shared model the prompt runs against. Only shared models are supported. + Example: 770e8400-e29b-41d4-a716-446655440002. + name (str): Customer-visible name of the routine. Used as the email subject for email destinations, and shown on + Slack deliveries. Example: Weekly user signups. + prompt (str): Natural language prompt Omni runs on each scheduled run. Example: How many users signed up last + week?. + schedule (str): Six-field cron expression (minute, hour, day-of-month, month, day-of-week, year; use `?` for an + unspecified day field). Minimum frequency is once per hour; contact Omni support if you need more frequent + scheduling. Example: 0 9 ? * MON *. + timezone (str): IANA timezone identifier used to evaluate the schedule. Example: America/New_York. + destination (RoutineEmailDestination | RoutineSlackDestination): Single delivery destination for the routine. To + send results to multiple destinations, create one routine per destination. Omni runs the prompt once per + scheduled run using the routine owner's permissions, and every recipient receives the same result regardless of + their own permissions. + branch_id (UUID | Unset): Optional branch ID for the model. Must be a branch of the shared model specified by + modelId. Example: 550e8400-e29b-41d4-a716-446655440000. + description (str | Unset): Optional human-readable notes about the routine. Display-only — never used as model + input. Example: Weekly signups summary for the growth team.. + topic_name (str | Unset): Topic name to scope query generation. If omitted, the AI picks the best topic. + Example: users. + """ + + model_id: UUID + name: str + prompt: str + schedule: str + timezone: str + destination: RoutineEmailDestination | RoutineSlackDestination + branch_id: UUID | Unset = UNSET + description: str | Unset = UNSET + topic_name: str | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + from ..models.routine_email_destination import RoutineEmailDestination + + model_id = str(self.model_id) + + name = self.name + + prompt = self.prompt + + schedule = self.schedule + + timezone = self.timezone + + destination: dict[str, Any] + if isinstance(self.destination, RoutineEmailDestination): + destination = self.destination.to_dict() + else: + destination = self.destination.to_dict() + + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + description = self.description + + topic_name = self.topic_name + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "modelId": model_id, + "name": name, + "prompt": prompt, + "schedule": schedule, + "timezone": timezone, + "destination": destination, + } + ) + if branch_id is not UNSET: + field_dict["branchId"] = branch_id + if description is not UNSET: + field_dict["description"] = description + if topic_name is not UNSET: + field_dict["topicName"] = topic_name + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.routine_email_destination import RoutineEmailDestination + from ..models.routine_slack_destination import RoutineSlackDestination + + d = dict(src_dict) + model_id = UUID(d.pop("modelId")) + + name = d.pop("name") + + prompt = d.pop("prompt") + + schedule = d.pop("schedule") + + timezone = d.pop("timezone") + + def _parse_destination(data: object) -> RoutineEmailDestination | RoutineSlackDestination: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_routine_destination_type_0 = RoutineEmailDestination.from_dict(data) + + return componentsschemas_routine_destination_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_routine_destination_type_1 = RoutineSlackDestination.from_dict(data) + + return componentsschemas_routine_destination_type_1 + + destination = _parse_destination(d.pop("destination")) + + _branch_id = d.pop("branchId", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + description = d.pop("description", UNSET) + + topic_name = d.pop("topicName", UNSET) + + routine_create_body = cls( + model_id=model_id, + name=name, + prompt=prompt, + schedule=schedule, + timezone=timezone, + destination=destination, + branch_id=branch_id, + description=description, + topic_name=topic_name, + ) + + return routine_create_body diff --git a/omni_python_sdk/models/routine_create_response.py b/omni_python_sdk/models/routine_create_response.py new file mode 100644 index 0000000..1eeb92b --- /dev/null +++ b/omni_python_sdk/models/routine_create_response.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="RoutineCreateResponse") + + +@_attrs_define +class RoutineCreateResponse: + """ + Attributes: + id (UUID): The unique identifier for the newly created routine. Example: 880e8400-e29b-41d4-a716-446655440003. + """ + + id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = UUID(d.pop("id")) + + routine_create_response = cls( + id=id, + ) + + routine_create_response.additional_properties = d + return routine_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/routine_delete_response.py b/omni_python_sdk/models/routine_delete_response.py new file mode 100644 index 0000000..152dc65 --- /dev/null +++ b/omni_python_sdk/models/routine_delete_response.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="RoutineDeleteResponse") + + +@_attrs_define +class RoutineDeleteResponse: + """ + Attributes: + deleted (bool): Always true on a successful delete. + id (UUID): The deleted routine’s ID. + """ + + deleted: bool + id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + deleted = self.deleted + + id = str(self.id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "deleted": deleted, + "id": id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + deleted = d.pop("deleted") + + id = UUID(d.pop("id")) + + routine_delete_response = cls( + deleted=deleted, + id=id, + ) + + routine_delete_response.additional_properties = d + return routine_delete_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/routine_email_destination.py b/omni_python_sdk/models/routine_email_destination.py new file mode 100644 index 0000000..d9b7323 --- /dev/null +++ b/omni_python_sdk/models/routine_email_destination.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define + +from ..models.routine_email_destination_type import RoutineEmailDestinationType, check_routine_email_destination_type +from ..types import UNSET, Unset + +T = TypeVar("T", bound="RoutineEmailDestination") + + +@_attrs_define +class RoutineEmailDestination: + """ + Attributes: + type_ (RoutineEmailDestinationType): Selects email delivery — each scheduled run is sent to the listed email + recipients and user groups. Example: email. + recipient_emails (list[str] | Unset): Email addresses that receive each scheduled run of the routine. Example: + ['alice@example.com', 'bob@example.com']. + user_group_ids (list[UUID] | Unset): User group IDs whose active members receive each scheduled run. Omni + expands each group to the members' current email addresses when the routine runs. Example: + ['550e8400-e29b-41d4-a716-446655440000']. + """ + + type_: RoutineEmailDestinationType + recipient_emails: list[str] | Unset = UNSET + user_group_ids: list[UUID] | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + type_: str = self.type_ + + recipient_emails: list[str] | Unset = UNSET + if not isinstance(self.recipient_emails, Unset): + recipient_emails = self.recipient_emails + + user_group_ids: list[str] | Unset = UNSET + if not isinstance(self.user_group_ids, Unset): + user_group_ids = [] + for user_group_ids_item_data in self.user_group_ids: + user_group_ids_item = str(user_group_ids_item_data) + user_group_ids.append(user_group_ids_item) + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "type": type_, + } + ) + if recipient_emails is not UNSET: + field_dict["recipientEmails"] = recipient_emails + if user_group_ids is not UNSET: + field_dict["userGroupIds"] = user_group_ids + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + type_ = check_routine_email_destination_type(d.pop("type")) + + recipient_emails = cast(list[str], d.pop("recipientEmails", UNSET)) + + _user_group_ids = d.pop("userGroupIds", UNSET) + user_group_ids: list[UUID] | Unset = UNSET + if _user_group_ids is not UNSET: + user_group_ids = [] + for user_group_ids_item_data in _user_group_ids: + user_group_ids_item = UUID(user_group_ids_item_data) + + user_group_ids.append(user_group_ids_item) + + routine_email_destination = cls( + type_=type_, + recipient_emails=recipient_emails, + user_group_ids=user_group_ids, + ) + + return routine_email_destination diff --git a/omni_python_sdk/models/routine_email_destination_response.py b/omni_python_sdk/models/routine_email_destination_response.py new file mode 100644 index 0000000..76fb1ee --- /dev/null +++ b/omni_python_sdk/models/routine_email_destination_response.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define + +from ..models.routine_email_destination_response_type import ( + RoutineEmailDestinationResponseType, + check_routine_email_destination_response_type, +) + +T = TypeVar("T", bound="RoutineEmailDestinationResponse") + + +@_attrs_define +class RoutineEmailDestinationResponse: + """ + Attributes: + recipient_emails (list[str]): Email addresses configured as direct recipients of each scheduled run, resolved + from their current membership. Example: ['alice@example.com', 'bob@example.com']. + type_ (RoutineEmailDestinationResponseType): Selects email delivery — each scheduled run is sent to the listed + email recipients and user groups. Example: email. + user_group_ids (list[UUID]): User group IDs whose active members receive each scheduled run. Omni expands each + group to the members' current email addresses when the routine runs. Example: + ['550e8400-e29b-41d4-a716-446655440000']. + """ + + recipient_emails: list[str] + type_: RoutineEmailDestinationResponseType + user_group_ids: list[UUID] + + def to_dict(self) -> dict[str, Any]: + recipient_emails = self.recipient_emails + + type_: str = self.type_ + + user_group_ids = [] + for user_group_ids_item_data in self.user_group_ids: + user_group_ids_item = str(user_group_ids_item_data) + user_group_ids.append(user_group_ids_item) + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "recipientEmails": recipient_emails, + "type": type_, + "userGroupIds": user_group_ids, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + recipient_emails = cast(list[str], d.pop("recipientEmails")) + + type_ = check_routine_email_destination_response_type(d.pop("type")) + + user_group_ids = [] + _user_group_ids = d.pop("userGroupIds") + for user_group_ids_item_data in _user_group_ids: + user_group_ids_item = UUID(user_group_ids_item_data) + + user_group_ids.append(user_group_ids_item) + + routine_email_destination_response = cls( + recipient_emails=recipient_emails, + type_=type_, + user_group_ids=user_group_ids, + ) + + return routine_email_destination_response diff --git a/omni_python_sdk/models/routine_email_destination_response_type.py b/omni_python_sdk/models/routine_email_destination_response_type.py new file mode 100644 index 0000000..9fd1723 --- /dev/null +++ b/omni_python_sdk/models/routine_email_destination_response_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +RoutineEmailDestinationResponseType = Literal["email"] + +ROUTINE_EMAIL_DESTINATION_RESPONSE_TYPE_VALUES: set[RoutineEmailDestinationResponseType] = { + "email", +} + + +def check_routine_email_destination_response_type(value: str) -> RoutineEmailDestinationResponseType: + if value in ROUTINE_EMAIL_DESTINATION_RESPONSE_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {ROUTINE_EMAIL_DESTINATION_RESPONSE_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/routine_email_destination_type.py b/omni_python_sdk/models/routine_email_destination_type.py new file mode 100644 index 0000000..c345ae7 --- /dev/null +++ b/omni_python_sdk/models/routine_email_destination_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +RoutineEmailDestinationType = Literal["email"] + +ROUTINE_EMAIL_DESTINATION_TYPE_VALUES: set[RoutineEmailDestinationType] = { + "email", +} + + +def check_routine_email_destination_type(value: str) -> RoutineEmailDestinationType: + if value in ROUTINE_EMAIL_DESTINATION_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {ROUTINE_EMAIL_DESTINATION_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/routine_last_run_type_0.py b/omni_python_sdk/models/routine_last_run_type_0.py new file mode 100644 index 0000000..8c2c39b --- /dev/null +++ b/omni_python_sdk/models/routine_last_run_type_0.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="RoutineLastRunType0") + + +@_attrs_define +class RoutineLastRunType0: + """Most recent completed run, or null if the routine has never completed a run. + + Attributes: + completed_at (None | str): ISO 8601 timestamp the last completed run finished. + label (str): Customer-visible status of the last completed run. Example: Delivered. + state (str): Machine-readable status of the last completed run. Example: COMPLETE. + """ + + completed_at: None | str + label: str + state: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + completed_at: None | str + completed_at = self.completed_at + + label = self.label + + state = self.state + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "completedAt": completed_at, + "label": label, + "state": state, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_completed_at(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + completed_at = _parse_completed_at(d.pop("completedAt")) + + label = d.pop("label") + + state = d.pop("state") + + routine_last_run_type_0 = cls( + completed_at=completed_at, + label=label, + state=state, + ) + + routine_last_run_type_0.additional_properties = d + return routine_last_run_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/routine_response.py b/omni_python_sdk/models/routine_response.py new file mode 100644 index 0000000..d9506aa --- /dev/null +++ b/omni_python_sdk/models/routine_response.py @@ -0,0 +1,279 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.routine_email_destination_response import RoutineEmailDestinationResponse + from ..models.routine_last_run_type_0 import RoutineLastRunType0 + from ..models.routine_slack_destination import RoutineSlackDestination + + +T = TypeVar("T", bound="RoutineResponse") + + +@_attrs_define +class RoutineResponse: + """ + Attributes: + branch_id (None | UUID): Branch of the shared model the prompt runs against, or null. + created_at (str): ISO 8601 timestamp when the routine was created. + description (None | str): Display-only notes about the routine, or null. + destination (RoutineEmailDestinationResponse | RoutineSlackDestination): Delivery configuration for the routine. + disabled (bool): Whether the owner has paused the routine. + id (UUID): The unique identifier of the routine. + last_run (None | RoutineLastRunType0): Most recent completed run, or null if the routine has never completed a + run. + model_id (UUID): The shared model the prompt runs against. + name (str): Customer-visible name of the routine. Used as the email subject for email destinations, and shown on + Slack deliveries. + prompt (str): Natural language prompt Omni runs on each scheduled run. + recipient_count (int): Number of distinct deliverable recipients. For email, user groups are expanded to members + and duplicates removed; a Slack routine is always 1 (its single channel or DM). + schedule (str): Six-field cron expression (minute, hour, day-of-month, month, day-of-week, year; use `?` for an + unspecified day field). + system_disabled (bool): Whether Omni disabled the routine because it could no longer run successfully or safely. + system_disabled_reason (None | str): Reason Omni disabled the routine, or null. + timezone (str): IANA timezone identifier used to evaluate the schedule. + topic_name (None | str): Topic scoping query generation, or null. + updated_at (str): ISO 8601 timestamp when the routine was last updated. + """ + + branch_id: None | UUID + created_at: str + description: None | str + destination: RoutineEmailDestinationResponse | RoutineSlackDestination + disabled: bool + id: UUID + last_run: None | RoutineLastRunType0 + model_id: UUID + name: str + prompt: str + recipient_count: int + schedule: str + system_disabled: bool + system_disabled_reason: None | str + timezone: str + topic_name: None | str + updated_at: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.routine_email_destination_response import RoutineEmailDestinationResponse + from ..models.routine_last_run_type_0 import RoutineLastRunType0 + + branch_id: None | str + if isinstance(self.branch_id, UUID): + branch_id = str(self.branch_id) + else: + branch_id = self.branch_id + + created_at = self.created_at + + description: None | str + description = self.description + + destination: dict[str, Any] + if isinstance(self.destination, RoutineEmailDestinationResponse): + destination = self.destination.to_dict() + else: + destination = self.destination.to_dict() + + disabled = self.disabled + + id = str(self.id) + + last_run: dict[str, Any] | None + if isinstance(self.last_run, RoutineLastRunType0): + last_run = self.last_run.to_dict() + else: + last_run = self.last_run + + model_id = str(self.model_id) + + name = self.name + + prompt = self.prompt + + recipient_count = self.recipient_count + + schedule = self.schedule + + system_disabled = self.system_disabled + + system_disabled_reason: None | str + system_disabled_reason = self.system_disabled_reason + + timezone = self.timezone + + topic_name: None | str + topic_name = self.topic_name + + updated_at = self.updated_at + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "branchId": branch_id, + "createdAt": created_at, + "description": description, + "destination": destination, + "disabled": disabled, + "id": id, + "lastRun": last_run, + "modelId": model_id, + "name": name, + "prompt": prompt, + "recipientCount": recipient_count, + "schedule": schedule, + "systemDisabled": system_disabled, + "systemDisabledReason": system_disabled_reason, + "timezone": timezone, + "topicName": topic_name, + "updatedAt": updated_at, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.routine_email_destination_response import RoutineEmailDestinationResponse + from ..models.routine_last_run_type_0 import RoutineLastRunType0 + from ..models.routine_slack_destination import RoutineSlackDestination + + d = dict(src_dict) + + def _parse_branch_id(data: object) -> None | UUID: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + branch_id_type_0 = UUID(data) + + return branch_id_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UUID, data) + + branch_id = _parse_branch_id(d.pop("branchId")) + + created_at = d.pop("createdAt") + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + def _parse_destination(data: object) -> RoutineEmailDestinationResponse | RoutineSlackDestination: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_routine_destination_response_type_0 = RoutineEmailDestinationResponse.from_dict(data) + + return componentsschemas_routine_destination_response_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_routine_destination_response_type_1 = RoutineSlackDestination.from_dict(data) + + return componentsschemas_routine_destination_response_type_1 + + destination = _parse_destination(d.pop("destination")) + + disabled = d.pop("disabled") + + id = UUID(d.pop("id")) + + def _parse_last_run(data: object) -> None | RoutineLastRunType0: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_routine_last_run_type_0 = RoutineLastRunType0.from_dict(data) + + return componentsschemas_routine_last_run_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | RoutineLastRunType0, data) + + last_run = _parse_last_run(d.pop("lastRun")) + + model_id = UUID(d.pop("modelId")) + + name = d.pop("name") + + prompt = d.pop("prompt") + + recipient_count = d.pop("recipientCount") + + schedule = d.pop("schedule") + + system_disabled = d.pop("systemDisabled") + + def _parse_system_disabled_reason(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + system_disabled_reason = _parse_system_disabled_reason(d.pop("systemDisabledReason")) + + timezone = d.pop("timezone") + + def _parse_topic_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + topic_name = _parse_topic_name(d.pop("topicName")) + + updated_at = d.pop("updatedAt") + + routine_response = cls( + branch_id=branch_id, + created_at=created_at, + description=description, + destination=destination, + disabled=disabled, + id=id, + last_run=last_run, + model_id=model_id, + name=name, + prompt=prompt, + recipient_count=recipient_count, + schedule=schedule, + system_disabled=system_disabled, + system_disabled_reason=system_disabled_reason, + timezone=timezone, + topic_name=topic_name, + updated_at=updated_at, + ) + + routine_response.additional_properties = d + return routine_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/routine_slack_destination.py b/omni_python_sdk/models/routine_slack_destination.py new file mode 100644 index 0000000..ee5aef3 --- /dev/null +++ b/omni_python_sdk/models/routine_slack_destination.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define + +from ..models.routine_slack_destination_slack_recipient_type import ( + RoutineSlackDestinationSlackRecipientType, + check_routine_slack_destination_slack_recipient_type, +) +from ..models.routine_slack_destination_type import RoutineSlackDestinationType, check_routine_slack_destination_type + +T = TypeVar("T", bound="RoutineSlackDestination") + + +@_attrs_define +class RoutineSlackDestination: + """ + Attributes: + recipient_id (str): The Slack channel ID (e.g. "C01234567") or user ID (e.g. "U01234567") that receives each + scheduled run. Exactly one recipient per Slack routine. Example: C01234567. + slack_recipient_type (RoutineSlackDestinationSlackRecipientType): Whether `recipientId` is a Slack channel or a + user (delivered as a direct message). Example: channel. + type_ (RoutineSlackDestinationType): Selects Slack delivery — each scheduled run is posted to one Slack channel + or sent as a direct message to one user. Example: slack. + """ + + recipient_id: str + slack_recipient_type: RoutineSlackDestinationSlackRecipientType + type_: RoutineSlackDestinationType + + def to_dict(self) -> dict[str, Any]: + recipient_id = self.recipient_id + + slack_recipient_type: str = self.slack_recipient_type + + type_: str = self.type_ + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "recipientId": recipient_id, + "slackRecipientType": slack_recipient_type, + "type": type_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + recipient_id = d.pop("recipientId") + + slack_recipient_type = check_routine_slack_destination_slack_recipient_type(d.pop("slackRecipientType")) + + type_ = check_routine_slack_destination_type(d.pop("type")) + + routine_slack_destination = cls( + recipient_id=recipient_id, + slack_recipient_type=slack_recipient_type, + type_=type_, + ) + + return routine_slack_destination diff --git a/omni_python_sdk/models/routine_slack_destination_slack_recipient_type.py b/omni_python_sdk/models/routine_slack_destination_slack_recipient_type.py new file mode 100644 index 0000000..a93b785 --- /dev/null +++ b/omni_python_sdk/models/routine_slack_destination_slack_recipient_type.py @@ -0,0 +1,16 @@ +from typing import Literal + +RoutineSlackDestinationSlackRecipientType = Literal["channel", "users"] + +ROUTINE_SLACK_DESTINATION_SLACK_RECIPIENT_TYPE_VALUES: set[RoutineSlackDestinationSlackRecipientType] = { + "channel", + "users", +} + + +def check_routine_slack_destination_slack_recipient_type(value: str) -> RoutineSlackDestinationSlackRecipientType: + if value in ROUTINE_SLACK_DESTINATION_SLACK_RECIPIENT_TYPE_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {ROUTINE_SLACK_DESTINATION_SLACK_RECIPIENT_TYPE_VALUES!r}" + ) diff --git a/omni_python_sdk/models/routine_slack_destination_type.py b/omni_python_sdk/models/routine_slack_destination_type.py new file mode 100644 index 0000000..1b7bb1c --- /dev/null +++ b/omni_python_sdk/models/routine_slack_destination_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +RoutineSlackDestinationType = Literal["slack"] + +ROUTINE_SLACK_DESTINATION_TYPE_VALUES: set[RoutineSlackDestinationType] = { + "slack", +} + + +def check_routine_slack_destination_type(value: str) -> RoutineSlackDestinationType: + if value in ROUTINE_SLACK_DESTINATION_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {ROUTINE_SLACK_DESTINATION_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/routine_trigger_response.py b/omni_python_sdk/models/routine_trigger_response.py new file mode 100644 index 0000000..009ccb8 --- /dev/null +++ b/omni_python_sdk/models/routine_trigger_response.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="RoutineTriggerResponse") + + +@_attrs_define +class RoutineTriggerResponse: + """ + Attributes: + id (UUID): The ID of the run (scheduled job) that was started. Example: 990e8400-e29b-41d4-a716-446655440004. + """ + + id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = UUID(d.pop("id")) + + routine_trigger_response = cls( + id=id, + ) + + routine_trigger_response.additional_properties = d + return routine_trigger_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/routine_update_body.py b/omni_python_sdk/models/routine_update_body.py new file mode 100644 index 0000000..bc8d3b2 --- /dev/null +++ b/omni_python_sdk/models/routine_update_body.py @@ -0,0 +1,137 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.routine_email_destination import RoutineEmailDestination + from ..models.routine_slack_destination import RoutineSlackDestination + + +T = TypeVar("T", bound="RoutineUpdateBody") + + +@_attrs_define +class RoutineUpdateBody: + """ + Attributes: + description (None | str | Unset): Display-only notes about the routine. Pass null to clear it. + destination (RoutineEmailDestination | RoutineSlackDestination | Unset): Single delivery destination for the + routine. To send results to multiple destinations, create one routine per destination. Omni runs the prompt once + per scheduled run using the routine owner's permissions, and every recipient receives the same result regardless + of their own permissions. + name (str | Unset): New customer-visible name of the routine. Used as the email subject for email destinations, + and shown on Slack deliveries. + prompt (str | Unset): New natural language prompt Omni runs on each scheduled run. + schedule (str | Unset): New six-field cron expression (minute, hour, day-of-month, month, day-of-week, year; use + `?` for an unspecified day field). Minimum frequency is once per hour. + timezone (str | Unset): New IANA timezone identifier used to evaluate the schedule. + """ + + description: None | str | Unset = UNSET + destination: RoutineEmailDestination | RoutineSlackDestination | Unset = UNSET + name: str | Unset = UNSET + prompt: str | Unset = UNSET + schedule: str | Unset = UNSET + timezone: str | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + from ..models.routine_email_destination import RoutineEmailDestination + + description: None | str | Unset + if isinstance(self.description, Unset): + description = UNSET + else: + description = self.description + + destination: dict[str, Any] | Unset + if isinstance(self.destination, Unset): + destination = UNSET + elif isinstance(self.destination, RoutineEmailDestination): + destination = self.destination.to_dict() + else: + destination = self.destination.to_dict() + + name = self.name + + prompt = self.prompt + + schedule = self.schedule + + timezone = self.timezone + + field_dict: dict[str, Any] = {} + + field_dict.update({}) + if description is not UNSET: + field_dict["description"] = description + if destination is not UNSET: + field_dict["destination"] = destination + if name is not UNSET: + field_dict["name"] = name + if prompt is not UNSET: + field_dict["prompt"] = prompt + if schedule is not UNSET: + field_dict["schedule"] = schedule + if timezone is not UNSET: + field_dict["timezone"] = timezone + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.routine_email_destination import RoutineEmailDestination + from ..models.routine_slack_destination import RoutineSlackDestination + + d = dict(src_dict) + + def _parse_description(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + description = _parse_description(d.pop("description", UNSET)) + + def _parse_destination(data: object) -> RoutineEmailDestination | RoutineSlackDestination | Unset: + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_routine_destination_type_0 = RoutineEmailDestination.from_dict(data) + + return componentsschemas_routine_destination_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_routine_destination_type_1 = RoutineSlackDestination.from_dict(data) + + return componentsschemas_routine_destination_type_1 + + destination = _parse_destination(d.pop("destination", UNSET)) + + name = d.pop("name", UNSET) + + prompt = d.pop("prompt", UNSET) + + schedule = d.pop("schedule", UNSET) + + timezone = d.pop("timezone", UNSET) + + routine_update_body = cls( + description=description, + destination=destination, + name=name, + prompt=prompt, + schedule=schedule, + timezone=timezone, + ) + + return routine_update_body diff --git a/omni_python_sdk/models/routines_list_response.py b/omni_python_sdk/models/routines_list_response.py new file mode 100644 index 0000000..d03f657 --- /dev/null +++ b/omni_python_sdk/models/routines_list_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.page_info import PageInfo + from ..models.routine_response import RoutineResponse + + +T = TypeVar("T", bound="RoutinesListResponse") + + +@_attrs_define +class RoutinesListResponse: + """ + Attributes: + page_info (PageInfo): + records (list[RoutineResponse]): Routines returned for this request, newest first. + """ + + page_info: PageInfo + records: list[RoutineResponse] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.page_info import PageInfo + from ..models.routine_response import RoutineResponse + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = RoutineResponse.from_dict(records_item_data) + + records.append(records_item) + + routines_list_response = cls( + page_info=page_info, + records=records, + ) + + routines_list_response.additional_properties = d + return routines_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/routines_list_sort_direction.py b/omni_python_sdk/models/routines_list_sort_direction.py new file mode 100644 index 0000000..55ad2bb --- /dev/null +++ b/omni_python_sdk/models/routines_list_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +RoutinesListSortDirection = Literal["asc", "desc"] + +ROUTINES_LIST_SORT_DIRECTION_VALUES: set[RoutinesListSortDirection] = { + "asc", + "desc", +} + + +def check_routines_list_sort_direction(value: str) -> RoutinesListSortDirection: + if value in ROUTINES_LIST_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {ROUTINES_LIST_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/schedule_suggestions_body.py b/omni_python_sdk/models/schedule_suggestions_body.py new file mode 100644 index 0000000..fc5d711 --- /dev/null +++ b/omni_python_sdk/models/schedule_suggestions_body.py @@ -0,0 +1,43 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ScheduleSuggestionsBody") + + +@_attrs_define +class ScheduleSuggestionsBody: + """ + Attributes: + timezone (str | Unset): IANA timezone the schedule fires in (e.g. `America/New_York`). Generation currently runs + once daily at ~2 AM in this timezone. Defaults to `UTC`. Default: 'UTC'. Example: America/New_York. + """ + + timezone: str | Unset = "UTC" + + def to_dict(self) -> dict[str, Any]: + timezone = self.timezone + + field_dict: dict[str, Any] = {} + + field_dict.update({}) + if timezone is not UNSET: + field_dict["timezone"] = timezone + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + timezone = d.pop("timezone", UNSET) + + schedule_suggestions_body = cls( + timezone=timezone, + ) + + return schedule_suggestions_body diff --git a/omni_python_sdk/models/schedule_suggestions_response.py b/omni_python_sdk/models/schedule_suggestions_response.py new file mode 100644 index 0000000..784e30a --- /dev/null +++ b/omni_python_sdk/models/schedule_suggestions_response.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.schedule_suggestions_response_status import ( + ScheduleSuggestionsResponseStatus, + check_schedule_suggestions_response_status, +) + +T = TypeVar("T", bound="ScheduleSuggestionsResponse") + + +@_attrs_define +class ScheduleSuggestionsResponse: + """ + Attributes: + id (UUID): The schedule (trigger) id. + shared_model_id (UUID): The shared model the schedule generates suggestions for. + status (ScheduleSuggestionsResponseStatus): + timezone (str): IANA timezone the schedule runs in. Example: America/New_York. + """ + + id: UUID + shared_model_id: UUID + status: ScheduleSuggestionsResponseStatus + timezone: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + shared_model_id = str(self.shared_model_id) + + status: str = self.status + + timezone = self.timezone + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "sharedModelId": shared_model_id, + "status": status, + "timezone": timezone, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = UUID(d.pop("id")) + + shared_model_id = UUID(d.pop("sharedModelId")) + + status = check_schedule_suggestions_response_status(d.pop("status")) + + timezone = d.pop("timezone") + + schedule_suggestions_response = cls( + id=id, + shared_model_id=shared_model_id, + status=status, + timezone=timezone, + ) + + schedule_suggestions_response.additional_properties = d + return schedule_suggestions_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedule_suggestions_response_status.py b/omni_python_sdk/models/schedule_suggestions_response_status.py new file mode 100644 index 0000000..865f941 --- /dev/null +++ b/omni_python_sdk/models/schedule_suggestions_response_status.py @@ -0,0 +1,13 @@ +from typing import Literal + +ScheduleSuggestionsResponseStatus = Literal["enabled"] + +SCHEDULE_SUGGESTIONS_RESPONSE_STATUS_VALUES: set[ScheduleSuggestionsResponseStatus] = { + "enabled", +} + + +def check_schedule_suggestions_response_status(value: str) -> ScheduleSuggestionsResponseStatus: + if value in SCHEDULE_SUGGESTIONS_RESPONSE_STATUS_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SCHEDULE_SUGGESTIONS_RESPONSE_STATUS_VALUES!r}") diff --git a/omni_python_sdk/models/schedules_add_recipients_body.py b/omni_python_sdk/models/schedules_add_recipients_body.py new file mode 100644 index 0000000..97504e6 --- /dev/null +++ b/omni_python_sdk/models/schedules_add_recipients_body.py @@ -0,0 +1,110 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="SchedulesAddRecipientsBody") + + +@_attrs_define +class SchedulesAddRecipientsBody: + """ + Attributes: + emails (list[str] | Unset): At least one email, userId, or userGroupId must be provided. Array of email + addresses to add as recipients. Example: ['user@example.com']. + user_group_ids (list[UUID] | Unset): At least one email, userId, or userGroupId must be provided. Array of user + group UUIDs to add as recipients. Example: ['123e4567-e89b-12d3-a456-426614174000']. + user_ids (list[UUID] | Unset): At least one email, userId, or userGroupId must be provided. Array of user UUIDs + to add as recipients. Use the List users and List embed users endpoints to retrieve user IDs. Example: + ['987fcdeb-51a2-43d7-9b56-254415f67890']. + """ + + emails: list[str] | Unset = UNSET + user_group_ids: list[UUID] | Unset = UNSET + user_ids: list[UUID] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + emails: list[str] | Unset = UNSET + if not isinstance(self.emails, Unset): + emails = self.emails + + user_group_ids: list[str] | Unset = UNSET + if not isinstance(self.user_group_ids, Unset): + user_group_ids = [] + for user_group_ids_item_data in self.user_group_ids: + user_group_ids_item = str(user_group_ids_item_data) + user_group_ids.append(user_group_ids_item) + + user_ids: list[str] | Unset = UNSET + if not isinstance(self.user_ids, Unset): + user_ids = [] + for user_ids_item_data in self.user_ids: + user_ids_item = str(user_ids_item_data) + user_ids.append(user_ids_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if emails is not UNSET: + field_dict["emails"] = emails + if user_group_ids is not UNSET: + field_dict["userGroupIds"] = user_group_ids + if user_ids is not UNSET: + field_dict["userIds"] = user_ids + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + emails = cast(list[str], d.pop("emails", UNSET)) + + _user_group_ids = d.pop("userGroupIds", UNSET) + user_group_ids: list[UUID] | Unset = UNSET + if _user_group_ids is not UNSET: + user_group_ids = [] + for user_group_ids_item_data in _user_group_ids: + user_group_ids_item = UUID(user_group_ids_item_data) + + user_group_ids.append(user_group_ids_item) + + _user_ids = d.pop("userIds", UNSET) + user_ids: list[UUID] | Unset = UNSET + if _user_ids is not UNSET: + user_ids = [] + for user_ids_item_data in _user_ids: + user_ids_item = UUID(user_ids_item_data) + + user_ids.append(user_ids_item) + + schedules_add_recipients_body = cls( + emails=emails, + user_group_ids=user_group_ids, + user_ids=user_ids, + ) + + schedules_add_recipients_body.additional_properties = d + return schedules_add_recipients_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_add_recipients_response.py b/omni_python_sdk/models/schedules_add_recipients_response.py new file mode 100644 index 0000000..7972d62 --- /dev/null +++ b/omni_python_sdk/models/schedules_add_recipients_response.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SchedulesAddRecipientsResponse") + + +@_attrs_define +class SchedulesAddRecipientsResponse: + """ + Attributes: + added_group_recipients_count (float): Number of user group recipients added. Example: 1. + added_recipients_count (float): Number of individual recipients added. Example: 2. + success (bool): Whether the operation was successful. Example: True. + """ + + added_group_recipients_count: float + added_recipients_count: float + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + added_group_recipients_count = self.added_group_recipients_count + + added_recipients_count = self.added_recipients_count + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "addedGroupRecipientsCount": added_group_recipients_count, + "addedRecipientsCount": added_recipients_count, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + added_group_recipients_count = d.pop("addedGroupRecipientsCount") + + added_recipients_count = d.pop("addedRecipientsCount") + + success = d.pop("success") + + schedules_add_recipients_response = cls( + added_group_recipients_count=added_group_recipients_count, + added_recipients_count=added_recipients_count, + success=success, + ) + + schedules_add_recipients_response.additional_properties = d + return schedules_add_recipients_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_create_schedules_create_body.py b/omni_python_sdk/models/schedules_create_schedules_create_body.py new file mode 100644 index 0000000..af93cad --- /dev/null +++ b/omni_python_sdk/models/schedules_create_schedules_create_body.py @@ -0,0 +1,340 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.schedules_create_schedules_create_body_condition_type import ( + SchedulesCreateSchedulesCreateBodyConditionType, + check_schedules_create_schedules_create_body_condition_type, +) +from ..models.schedules_create_schedules_create_body_destination_type import ( + SchedulesCreateSchedulesCreateBodyDestinationType, + check_schedules_create_schedules_create_body_destination_type, +) +from ..models.schedules_create_schedules_create_body_format import ( + SchedulesCreateSchedulesCreateBodyFormat, + check_schedules_create_schedules_create_body_format, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.schedules_create_schedules_create_body_recipients_item import ( + SchedulesCreateSchedulesCreateBodyRecipientsItem, + ) + + +T = TypeVar("T", bound="SchedulesCreateSchedulesCreateBody") + + +@_attrs_define +class SchedulesCreateSchedulesCreateBody: + """Request body for creating a scheduled task. Required fields vary by destinationType. + + Attributes: + destination_type (SchedulesCreateSchedulesCreateBodyDestinationType): The delivery destination type Example: + email. + format_ (SchedulesCreateSchedulesCreateBodyFormat): The output format: link_only, pdf, png, csv, xlsx, json + Example: pdf. + identifier (str): The ID of the dashboard to schedule Example: 12db1a0a. + name (str): The name of the scheduled task Example: Weekly Sales Report. + schedule (str): AWS EventBridge cron expression (minute hour day-of-month month day-of-week year) Example: 0 9 ? + * MON *. + timezone (str): IANA timezone for the schedule Example: America/New_York. + bucket_name (str | Unset): S3 bucket name (S3 destination only). Must be 3-63 characters, lowercase. Example: + my-reports-bucket. + condition_query_map_key (str | Unset): The ID of the query to monitor for triggering an alert. Required if + conditionType is provided. Example: Jmn2r3KV. + condition_type (SchedulesCreateSchedulesCreateBodyConditionType | Unset): Defines the type of condition to use + for alerts. Required if conditionQueryMapKey is provided. Example: RESULTS_PRESENT. + enable_formatting (bool | Unset): If true, formatting will be enabled in the output + fan_out (bool | Unset): If true, send personalized emails to each recipient (email only) + filter_config (Any | Unset): Filter conditions to apply to the task Example: {'status': ['active', 'pending']}. + hide_hidden_fields (bool | Unset): If true, hidden fields won't be displayed (csv/xlsx only) + hide_title (bool | Unset): If true, hide the title in output (pdf/png only) + key_prefix (str | Unset): S3 key prefix / folder path (S3 destination only). Leading slashes are normalized. + Example: reports/weekly/. + kill_jobs_on_failure (bool | Unset): If true, stop entire job if any queries fail + recipients (list[SchedulesCreateSchedulesCreateBodyRecipientsItem] | Unset): Email recipients (email destination + only). For Slack destinations, use the "recipients" field with a channel ID string or user ID(s) as a string or + array. + region (str | Unset): AWS region where the S3 bucket is located (S3 destination only). Example: us-east-1. + role_arn (str | Unset): ARN of the cross-account IAM role Omni will assume to write to the S3 bucket (S3 + destination only). Example: arn:aws:iam::123456789012:role/OmniS3DeliveryRole. + show_content_link (bool | Unset): If true, include a link to the content Example: True. + show_filters (bool | Unset): If true, show applied filters in output Example: True. + slack_recipient_type (str | Unset): Slack recipient type (Slack destination only). Use "channel" to deliver to a + single Slack channel, or "users" to deliver to one or more Slack users via direct message. Example: channel. + test_now (bool | Unset): If true, run immediately instead of scheduling + timezone_override (None | str | Unset): Optional IANA timezone applied to query execution at render time. + Distinct from `timezone` (which controls *when* the schedule fires). Omit or pass null for no override. Example: + Europe/Paris. + webhook_url (str | Unset): Webhook URL (webhook destination only) Example: https://example.com/webhook. + """ + + destination_type: SchedulesCreateSchedulesCreateBodyDestinationType + format_: SchedulesCreateSchedulesCreateBodyFormat + identifier: str + name: str + schedule: str + timezone: str + bucket_name: str | Unset = UNSET + condition_query_map_key: str | Unset = UNSET + condition_type: SchedulesCreateSchedulesCreateBodyConditionType | Unset = UNSET + enable_formatting: bool | Unset = UNSET + fan_out: bool | Unset = UNSET + filter_config: Any | Unset = UNSET + hide_hidden_fields: bool | Unset = UNSET + hide_title: bool | Unset = UNSET + key_prefix: str | Unset = UNSET + kill_jobs_on_failure: bool | Unset = UNSET + recipients: list[SchedulesCreateSchedulesCreateBodyRecipientsItem] | Unset = UNSET + region: str | Unset = UNSET + role_arn: str | Unset = UNSET + show_content_link: bool | Unset = UNSET + show_filters: bool | Unset = UNSET + slack_recipient_type: str | Unset = UNSET + test_now: bool | Unset = UNSET + timezone_override: None | str | Unset = UNSET + webhook_url: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + destination_type: str = self.destination_type + + format_: str = self.format_ + + identifier = self.identifier + + name = self.name + + schedule = self.schedule + + timezone = self.timezone + + bucket_name = self.bucket_name + + condition_query_map_key = self.condition_query_map_key + + condition_type: str | Unset = UNSET + if not isinstance(self.condition_type, Unset): + condition_type = self.condition_type + + enable_formatting = self.enable_formatting + + fan_out = self.fan_out + + filter_config = self.filter_config + + hide_hidden_fields = self.hide_hidden_fields + + hide_title = self.hide_title + + key_prefix = self.key_prefix + + kill_jobs_on_failure = self.kill_jobs_on_failure + + recipients: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.recipients, Unset): + recipients = [] + for recipients_item_data in self.recipients: + recipients_item = recipients_item_data.to_dict() + recipients.append(recipients_item) + + region = self.region + + role_arn = self.role_arn + + show_content_link = self.show_content_link + + show_filters = self.show_filters + + slack_recipient_type = self.slack_recipient_type + + test_now = self.test_now + + timezone_override: None | str | Unset + if isinstance(self.timezone_override, Unset): + timezone_override = UNSET + else: + timezone_override = self.timezone_override + + webhook_url = self.webhook_url + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "destinationType": destination_type, + "format": format_, + "identifier": identifier, + "name": name, + "schedule": schedule, + "timezone": timezone, + } + ) + if bucket_name is not UNSET: + field_dict["bucketName"] = bucket_name + if condition_query_map_key is not UNSET: + field_dict["conditionQueryMapKey"] = condition_query_map_key + if condition_type is not UNSET: + field_dict["conditionType"] = condition_type + if enable_formatting is not UNSET: + field_dict["enableFormatting"] = enable_formatting + if fan_out is not UNSET: + field_dict["fanOut"] = fan_out + if filter_config is not UNSET: + field_dict["filterConfig"] = filter_config + if hide_hidden_fields is not UNSET: + field_dict["hideHiddenFields"] = hide_hidden_fields + if hide_title is not UNSET: + field_dict["hideTitle"] = hide_title + if key_prefix is not UNSET: + field_dict["keyPrefix"] = key_prefix + if kill_jobs_on_failure is not UNSET: + field_dict["killJobsOnFailure"] = kill_jobs_on_failure + if recipients is not UNSET: + field_dict["recipients"] = recipients + if region is not UNSET: + field_dict["region"] = region + if role_arn is not UNSET: + field_dict["roleArn"] = role_arn + if show_content_link is not UNSET: + field_dict["showContentLink"] = show_content_link + if show_filters is not UNSET: + field_dict["showFilters"] = show_filters + if slack_recipient_type is not UNSET: + field_dict["slackRecipientType"] = slack_recipient_type + if test_now is not UNSET: + field_dict["testNow"] = test_now + if timezone_override is not UNSET: + field_dict["timezoneOverride"] = timezone_override + if webhook_url is not UNSET: + field_dict["webhookUrl"] = webhook_url + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.schedules_create_schedules_create_body_recipients_item import ( + SchedulesCreateSchedulesCreateBodyRecipientsItem, + ) + + d = dict(src_dict) + destination_type = check_schedules_create_schedules_create_body_destination_type(d.pop("destinationType")) + + format_ = check_schedules_create_schedules_create_body_format(d.pop("format")) + + identifier = d.pop("identifier") + + name = d.pop("name") + + schedule = d.pop("schedule") + + timezone = d.pop("timezone") + + bucket_name = d.pop("bucketName", UNSET) + + condition_query_map_key = d.pop("conditionQueryMapKey", UNSET) + + _condition_type = d.pop("conditionType", UNSET) + condition_type: SchedulesCreateSchedulesCreateBodyConditionType | Unset + if isinstance(_condition_type, Unset): + condition_type = UNSET + else: + condition_type = check_schedules_create_schedules_create_body_condition_type(_condition_type) + + enable_formatting = d.pop("enableFormatting", UNSET) + + fan_out = d.pop("fanOut", UNSET) + + filter_config = d.pop("filterConfig", UNSET) + + hide_hidden_fields = d.pop("hideHiddenFields", UNSET) + + hide_title = d.pop("hideTitle", UNSET) + + key_prefix = d.pop("keyPrefix", UNSET) + + kill_jobs_on_failure = d.pop("killJobsOnFailure", UNSET) + + _recipients = d.pop("recipients", UNSET) + recipients: list[SchedulesCreateSchedulesCreateBodyRecipientsItem] | Unset = UNSET + if _recipients is not UNSET: + recipients = [] + for recipients_item_data in _recipients: + recipients_item = SchedulesCreateSchedulesCreateBodyRecipientsItem.from_dict(recipients_item_data) + + recipients.append(recipients_item) + + region = d.pop("region", UNSET) + + role_arn = d.pop("roleArn", UNSET) + + show_content_link = d.pop("showContentLink", UNSET) + + show_filters = d.pop("showFilters", UNSET) + + slack_recipient_type = d.pop("slackRecipientType", UNSET) + + test_now = d.pop("testNow", UNSET) + + def _parse_timezone_override(data: object) -> None | str | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(None | str | Unset, data) + + timezone_override = _parse_timezone_override(d.pop("timezoneOverride", UNSET)) + + webhook_url = d.pop("webhookUrl", UNSET) + + schedules_create_schedules_create_body = cls( + destination_type=destination_type, + format_=format_, + identifier=identifier, + name=name, + schedule=schedule, + timezone=timezone, + bucket_name=bucket_name, + condition_query_map_key=condition_query_map_key, + condition_type=condition_type, + enable_formatting=enable_formatting, + fan_out=fan_out, + filter_config=filter_config, + hide_hidden_fields=hide_hidden_fields, + hide_title=hide_title, + key_prefix=key_prefix, + kill_jobs_on_failure=kill_jobs_on_failure, + recipients=recipients, + region=region, + role_arn=role_arn, + show_content_link=show_content_link, + show_filters=show_filters, + slack_recipient_type=slack_recipient_type, + test_now=test_now, + timezone_override=timezone_override, + webhook_url=webhook_url, + ) + + schedules_create_schedules_create_body.additional_properties = d + return schedules_create_schedules_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_create_schedules_create_body_condition_type.py b/omni_python_sdk/models/schedules_create_schedules_create_body_condition_type.py new file mode 100644 index 0000000..d46b1e4 --- /dev/null +++ b/omni_python_sdk/models/schedules_create_schedules_create_body_condition_type.py @@ -0,0 +1,22 @@ +from typing import Literal + +SchedulesCreateSchedulesCreateBodyConditionType = Literal[ + "RESULTS_CHANGED", "RESULTS_MISSING", "RESULTS_PRESENT", "RESULTS_UNCHANGED" +] + +SCHEDULES_CREATE_SCHEDULES_CREATE_BODY_CONDITION_TYPE_VALUES: set[SchedulesCreateSchedulesCreateBodyConditionType] = { + "RESULTS_CHANGED", + "RESULTS_MISSING", + "RESULTS_PRESENT", + "RESULTS_UNCHANGED", +} + + +def check_schedules_create_schedules_create_body_condition_type( + value: str, +) -> SchedulesCreateSchedulesCreateBodyConditionType: + if value in SCHEDULES_CREATE_SCHEDULES_CREATE_BODY_CONDITION_TYPE_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SCHEDULES_CREATE_SCHEDULES_CREATE_BODY_CONDITION_TYPE_VALUES!r}" + ) diff --git a/omni_python_sdk/models/schedules_create_schedules_create_body_destination_type.py b/omni_python_sdk/models/schedules_create_schedules_create_body_destination_type.py new file mode 100644 index 0000000..4856318 --- /dev/null +++ b/omni_python_sdk/models/schedules_create_schedules_create_body_destination_type.py @@ -0,0 +1,23 @@ +from typing import Literal + +SchedulesCreateSchedulesCreateBodyDestinationType = Literal["email", "s3", "sftp", "slack", "webhook"] + +SCHEDULES_CREATE_SCHEDULES_CREATE_BODY_DESTINATION_TYPE_VALUES: set[ + SchedulesCreateSchedulesCreateBodyDestinationType +] = { + "email", + "s3", + "sftp", + "slack", + "webhook", +} + + +def check_schedules_create_schedules_create_body_destination_type( + value: str, +) -> SchedulesCreateSchedulesCreateBodyDestinationType: + if value in SCHEDULES_CREATE_SCHEDULES_CREATE_BODY_DESTINATION_TYPE_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SCHEDULES_CREATE_SCHEDULES_CREATE_BODY_DESTINATION_TYPE_VALUES!r}" + ) diff --git a/omni_python_sdk/models/schedules_create_schedules_create_body_format.py b/omni_python_sdk/models/schedules_create_schedules_create_body_format.py new file mode 100644 index 0000000..4de2b14 --- /dev/null +++ b/omni_python_sdk/models/schedules_create_schedules_create_body_format.py @@ -0,0 +1,20 @@ +from typing import Literal + +SchedulesCreateSchedulesCreateBodyFormat = Literal["csv", "json", "link_only", "pdf", "png", "xlsx"] + +SCHEDULES_CREATE_SCHEDULES_CREATE_BODY_FORMAT_VALUES: set[SchedulesCreateSchedulesCreateBodyFormat] = { + "csv", + "json", + "link_only", + "pdf", + "png", + "xlsx", +} + + +def check_schedules_create_schedules_create_body_format(value: str) -> SchedulesCreateSchedulesCreateBodyFormat: + if value in SCHEDULES_CREATE_SCHEDULES_CREATE_BODY_FORMAT_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SCHEDULES_CREATE_SCHEDULES_CREATE_BODY_FORMAT_VALUES!r}" + ) diff --git a/omni_python_sdk/models/schedules_create_schedules_create_body_recipients_item.py b/omni_python_sdk/models/schedules_create_schedules_create_body_recipients_item.py new file mode 100644 index 0000000..438eb7f --- /dev/null +++ b/omni_python_sdk/models/schedules_create_schedules_create_body_recipients_item.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SchedulesCreateSchedulesCreateBodyRecipientsItem") + + +@_attrs_define +class SchedulesCreateSchedulesCreateBodyRecipientsItem: + """ + Attributes: + email (str): Recipient email address Example: user@example.com. + """ + + email: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + email = self.email + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "email": email, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + email = d.pop("email") + + schedules_create_schedules_create_body_recipients_item = cls( + email=email, + ) + + schedules_create_schedules_create_body_recipients_item.additional_properties = d + return schedules_create_schedules_create_body_recipients_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_create_schedules_create_response.py b/omni_python_sdk/models/schedules_create_schedules_create_response.py new file mode 100644 index 0000000..07d8ef1 --- /dev/null +++ b/omni_python_sdk/models/schedules_create_schedules_create_response.py @@ -0,0 +1,111 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="SchedulesCreateSchedulesCreateResponse") + + +@_attrs_define +class SchedulesCreateSchedulesCreateResponse: + """Create schedule response + + Attributes: + message (str): Success message Example: Successfully created schedule. + deliverer_role_arn (str | Unset): The ARN of the Omni deliverer role. Use this as the Principal in your IAM role + trust policy. Only returned for S3 destinations. Example: + arn:aws:iam::529831494235:role/OmniSchedulerDelivererRole. + external_id (UUID | Unset): The organization ID used as the external ID for confused deputy prevention. Add this + to your IAM role trust policy as the sts:ExternalId condition. Static across all S3 destinations for your + organization. Only returned for S3 destinations. Example: 550e8400-e29b-41d4-a716-446655440000. + id (UUID | Unset): Created schedule ID (only when testNow is false) Example: + 123e4567-e89b-12d3-a456-426614174000. + """ + + message: str + deliverer_role_arn: str | Unset = UNSET + external_id: UUID | Unset = UNSET + id: UUID | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + message = self.message + + deliverer_role_arn = self.deliverer_role_arn + + external_id: str | Unset = UNSET + if not isinstance(self.external_id, Unset): + external_id = str(self.external_id) + + id: str | Unset = UNSET + if not isinstance(self.id, Unset): + id = str(self.id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "message": message, + } + ) + if deliverer_role_arn is not UNSET: + field_dict["delivererRoleArn"] = deliverer_role_arn + if external_id is not UNSET: + field_dict["externalId"] = external_id + if id is not UNSET: + field_dict["id"] = id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + message = d.pop("message") + + deliverer_role_arn = d.pop("delivererRoleArn", UNSET) + + _external_id = d.pop("externalId", UNSET) + external_id: UUID | Unset + if isinstance(_external_id, Unset): + external_id = UNSET + else: + external_id = UUID(_external_id) + + _id = d.pop("id", UNSET) + id: UUID | Unset + if isinstance(_id, Unset): + id = UNSET + else: + id = UUID(_id) + + schedules_create_schedules_create_response = cls( + message=message, + deliverer_role_arn=deliverer_role_arn, + external_id=external_id, + id=id, + ) + + schedules_create_schedules_create_response.additional_properties = d + return schedules_create_schedules_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_get_destination.py b/omni_python_sdk/models/schedules_get_destination.py new file mode 100644 index 0000000..0aa743c --- /dev/null +++ b/omni_python_sdk/models/schedules_get_destination.py @@ -0,0 +1,151 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.schedules_get_recipient import SchedulesGetRecipient + + +T = TypeVar("T", bound="SchedulesGetDestination") + + +@_attrs_define +class SchedulesGetDestination: + """ + Attributes: + format_ (str): Output format: pdf, png, csv, xlsx, json, link_only Example: pdf. + id (UUID): Destination UUID + last_completed_at (datetime.datetime | None): Timestamp of last completed delivery + last_status (None | str): Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET + recipients (list[SchedulesGetRecipient]): Individual email recipients + user_group_recipients (list[Any]): User group recipients + metadata (Any | Unset): Destination-specific configuration (type, recipients, credentials, etc.) + """ + + format_: str + id: UUID + last_completed_at: datetime.datetime | None + last_status: None | str + recipients: list[SchedulesGetRecipient] + user_group_recipients: list[Any] + metadata: Any | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + format_ = self.format_ + + id = str(self.id) + + last_completed_at: None | str + if isinstance(self.last_completed_at, datetime.datetime): + last_completed_at = self.last_completed_at.isoformat() + else: + last_completed_at = self.last_completed_at + + last_status: None | str + last_status = self.last_status + + recipients = [] + for recipients_item_data in self.recipients: + recipients_item = recipients_item_data.to_dict() + recipients.append(recipients_item) + + user_group_recipients = self.user_group_recipients + + metadata = self.metadata + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "format": format_, + "id": id, + "lastCompletedAt": last_completed_at, + "lastStatus": last_status, + "recipients": recipients, + "userGroupRecipients": user_group_recipients, + } + ) + if metadata is not UNSET: + field_dict["metadata"] = metadata + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.schedules_get_recipient import SchedulesGetRecipient + + d = dict(src_dict) + format_ = d.pop("format") + + id = UUID(d.pop("id")) + + def _parse_last_completed_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + last_completed_at_type_0 = datetime.datetime.fromisoformat(data) + + return last_completed_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + last_completed_at = _parse_last_completed_at(d.pop("lastCompletedAt")) + + def _parse_last_status(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + last_status = _parse_last_status(d.pop("lastStatus")) + + recipients = [] + _recipients = d.pop("recipients") + for recipients_item_data in _recipients: + recipients_item = SchedulesGetRecipient.from_dict(recipients_item_data) + + recipients.append(recipients_item) + + user_group_recipients = cast(list[Any], d.pop("userGroupRecipients")) + + metadata = d.pop("metadata", UNSET) + + schedules_get_destination = cls( + format_=format_, + id=id, + last_completed_at=last_completed_at, + last_status=last_status, + recipients=recipients, + user_group_recipients=user_group_recipients, + metadata=metadata, + ) + + schedules_get_destination.additional_properties = d + return schedules_get_destination + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_get_recipient.py b/omni_python_sdk/models/schedules_get_recipient.py new file mode 100644 index 0000000..c660a1f --- /dev/null +++ b/omni_python_sdk/models/schedules_get_recipient.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.schedules_get_recipient_membership import SchedulesGetRecipientMembership + + +T = TypeVar("T", bound="SchedulesGetRecipient") + + +@_attrs_define +class SchedulesGetRecipient: + """ + Attributes: + id (UUID): Recipient ID + membership (SchedulesGetRecipientMembership): + membership_id (UUID): Membership ID + """ + + id: UUID + membership: SchedulesGetRecipientMembership + membership_id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + membership = self.membership.to_dict() + + membership_id = str(self.membership_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "membership": membership, + "membershipId": membership_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.schedules_get_recipient_membership import SchedulesGetRecipientMembership + + d = dict(src_dict) + id = UUID(d.pop("id")) + + membership = SchedulesGetRecipientMembership.from_dict(d.pop("membership")) + + membership_id = UUID(d.pop("membershipId")) + + schedules_get_recipient = cls( + id=id, + membership=membership, + membership_id=membership_id, + ) + + schedules_get_recipient.additional_properties = d + return schedules_get_recipient + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_get_recipient_membership.py b/omni_python_sdk/models/schedules_get_recipient_membership.py new file mode 100644 index 0000000..ef8b507 --- /dev/null +++ b/omni_python_sdk/models/schedules_get_recipient_membership.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.schedules_get_recipient_membership_user import SchedulesGetRecipientMembershipUser + + +T = TypeVar("T", bound="SchedulesGetRecipientMembership") + + +@_attrs_define +class SchedulesGetRecipientMembership: + """ + Attributes: + user (SchedulesGetRecipientMembershipUser): + """ + + user: SchedulesGetRecipientMembershipUser + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + user = self.user.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "user": user, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.schedules_get_recipient_membership_user import SchedulesGetRecipientMembershipUser + + d = dict(src_dict) + user = SchedulesGetRecipientMembershipUser.from_dict(d.pop("user")) + + schedules_get_recipient_membership = cls( + user=user, + ) + + schedules_get_recipient_membership.additional_properties = d + return schedules_get_recipient_membership + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_get_recipient_membership_user.py b/omni_python_sdk/models/schedules_get_recipient_membership_user.py new file mode 100644 index 0000000..2d76398 --- /dev/null +++ b/omni_python_sdk/models/schedules_get_recipient_membership_user.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SchedulesGetRecipientMembershipUser") + + +@_attrs_define +class SchedulesGetRecipientMembershipUser: + """ + Attributes: + email (str): Recipient email + name (None | str): Recipient name + """ + + email: str + name: None | str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + email = self.email + + name: None | str + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "email": email, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + email = d.pop("email") + + def _parse_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + name = _parse_name(d.pop("name")) + + schedules_get_recipient_membership_user = cls( + email=email, + name=name, + ) + + schedules_get_recipient_membership_user.additional_properties = d + return schedules_get_recipient_membership_user + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_get_response.py b/omni_python_sdk/models/schedules_get_response.py new file mode 100644 index 0000000..4b6038c --- /dev/null +++ b/omni_python_sdk/models/schedules_get_response.py @@ -0,0 +1,294 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.schedules_get_destination import SchedulesGetDestination + from ..models.schedules_get_response_owner import SchedulesGetResponseOwner + + +T = TypeVar("T", bound="SchedulesGetResponse") + + +@_attrs_define +class SchedulesGetResponse: + """ + Attributes: + condition_query_map_key (None | str): Query key used for alert condition (null for standard schedules) + condition_type (None | str): Alert condition type: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING + created_at (datetime.datetime): Creation timestamp + destinations (list[SchedulesGetDestination]): Delivery destination configurations + disabled_at (datetime.datetime | None): Timestamp when the schedule was paused (null if active) + entity_id (str): ID of the associated dashboard + fan_out (bool): Whether personalized fan-out delivery is enabled + id (UUID): Schedule UUID Example: 123e4567-e89b-12d3-a456-426614174000. + kill_jobs_on_failure (bool): Whether to stop the job if any queries fail + name (str): Schedule name Example: Weekly Sales Report. + organization_id (UUID): Organization UUID + owner (SchedulesGetResponseOwner): + owner_id (UUID): User ID of the schedule owner + schedule (str): AWS EventBridge cron expression (minute hour day-of-month month day-of-week year) Example: 0 9 ? + * MON *. + system_disabled_at (datetime.datetime | None): Timestamp when the system disabled the schedule + system_disabled_reason (None | str): Reason for system disabling: missingQuery, noAccess, + orphanedFilterConfigKeys + timezone (str): IANA timezone for the schedule Example: America/New_York. + updated_at (datetime.datetime): Last update timestamp + filter_config (Any | Unset): The effective dashboard filter configuration that the schedule will run with: the + dashboard's current default filters merged under the schedule's persisted overrides, with any keys no longer + present on the dashboard dropped. This matches what is shown when the schedule is opened in the Edit Delivery + panel, and may differ from the schedule's persisted filter configuration. + metadata (Any | Unset): Schedule metadata including format options and delivery settings. Includes + `timezoneOverride` (IANA timezone applied to query execution at render time, or null when no override is set). + """ + + condition_query_map_key: None | str + condition_type: None | str + created_at: datetime.datetime + destinations: list[SchedulesGetDestination] + disabled_at: datetime.datetime | None + entity_id: str + fan_out: bool + id: UUID + kill_jobs_on_failure: bool + name: str + organization_id: UUID + owner: SchedulesGetResponseOwner + owner_id: UUID + schedule: str + system_disabled_at: datetime.datetime | None + system_disabled_reason: None | str + timezone: str + updated_at: datetime.datetime + filter_config: Any | Unset = UNSET + metadata: Any | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + condition_query_map_key: None | str + condition_query_map_key = self.condition_query_map_key + + condition_type: None | str + condition_type = self.condition_type + + created_at = self.created_at.isoformat() + + destinations = [] + for destinations_item_data in self.destinations: + destinations_item = destinations_item_data.to_dict() + destinations.append(destinations_item) + + disabled_at: None | str + if isinstance(self.disabled_at, datetime.datetime): + disabled_at = self.disabled_at.isoformat() + else: + disabled_at = self.disabled_at + + entity_id = self.entity_id + + fan_out = self.fan_out + + id = str(self.id) + + kill_jobs_on_failure = self.kill_jobs_on_failure + + name = self.name + + organization_id = str(self.organization_id) + + owner = self.owner.to_dict() + + owner_id = str(self.owner_id) + + schedule = self.schedule + + system_disabled_at: None | str + if isinstance(self.system_disabled_at, datetime.datetime): + system_disabled_at = self.system_disabled_at.isoformat() + else: + system_disabled_at = self.system_disabled_at + + system_disabled_reason: None | str + system_disabled_reason = self.system_disabled_reason + + timezone = self.timezone + + updated_at = self.updated_at.isoformat() + + filter_config = self.filter_config + + metadata = self.metadata + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "conditionQueryMapKey": condition_query_map_key, + "conditionType": condition_type, + "createdAt": created_at, + "destinations": destinations, + "disabledAt": disabled_at, + "entityId": entity_id, + "fanOut": fan_out, + "id": id, + "killJobsOnFailure": kill_jobs_on_failure, + "name": name, + "organizationId": organization_id, + "owner": owner, + "ownerId": owner_id, + "schedule": schedule, + "systemDisabledAt": system_disabled_at, + "systemDisabledReason": system_disabled_reason, + "timezone": timezone, + "updatedAt": updated_at, + } + ) + if filter_config is not UNSET: + field_dict["filterConfig"] = filter_config + if metadata is not UNSET: + field_dict["metadata"] = metadata + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.schedules_get_destination import SchedulesGetDestination + from ..models.schedules_get_response_owner import SchedulesGetResponseOwner + + d = dict(src_dict) + + def _parse_condition_query_map_key(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + condition_query_map_key = _parse_condition_query_map_key(d.pop("conditionQueryMapKey")) + + def _parse_condition_type(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + condition_type = _parse_condition_type(d.pop("conditionType")) + + created_at = datetime.datetime.fromisoformat(d.pop("createdAt")) + + destinations = [] + _destinations = d.pop("destinations") + for destinations_item_data in _destinations: + destinations_item = SchedulesGetDestination.from_dict(destinations_item_data) + + destinations.append(destinations_item) + + def _parse_disabled_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + disabled_at_type_0 = datetime.datetime.fromisoformat(data) + + return disabled_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + disabled_at = _parse_disabled_at(d.pop("disabledAt")) + + entity_id = d.pop("entityId") + + fan_out = d.pop("fanOut") + + id = UUID(d.pop("id")) + + kill_jobs_on_failure = d.pop("killJobsOnFailure") + + name = d.pop("name") + + organization_id = UUID(d.pop("organizationId")) + + owner = SchedulesGetResponseOwner.from_dict(d.pop("owner")) + + owner_id = UUID(d.pop("ownerId")) + + schedule = d.pop("schedule") + + def _parse_system_disabled_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + system_disabled_at_type_0 = datetime.datetime.fromisoformat(data) + + return system_disabled_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + system_disabled_at = _parse_system_disabled_at(d.pop("systemDisabledAt")) + + def _parse_system_disabled_reason(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + system_disabled_reason = _parse_system_disabled_reason(d.pop("systemDisabledReason")) + + timezone = d.pop("timezone") + + updated_at = datetime.datetime.fromisoformat(d.pop("updatedAt")) + + filter_config = d.pop("filterConfig", UNSET) + + metadata = d.pop("metadata", UNSET) + + schedules_get_response = cls( + condition_query_map_key=condition_query_map_key, + condition_type=condition_type, + created_at=created_at, + destinations=destinations, + disabled_at=disabled_at, + entity_id=entity_id, + fan_out=fan_out, + id=id, + kill_jobs_on_failure=kill_jobs_on_failure, + name=name, + organization_id=organization_id, + owner=owner, + owner_id=owner_id, + schedule=schedule, + system_disabled_at=system_disabled_at, + system_disabled_reason=system_disabled_reason, + timezone=timezone, + updated_at=updated_at, + filter_config=filter_config, + metadata=metadata, + ) + + schedules_get_response.additional_properties = d + return schedules_get_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_get_response_owner.py b/omni_python_sdk/models/schedules_get_response_owner.py new file mode 100644 index 0000000..d67f6e0 --- /dev/null +++ b/omni_python_sdk/models/schedules_get_response_owner.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SchedulesGetResponseOwner") + + +@_attrs_define +class SchedulesGetResponseOwner: + """ + Attributes: + name (str): Schedule owner name + """ + + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + name = d.pop("name") + + schedules_get_response_owner = cls( + name=name, + ) + + schedules_get_response_owner.additional_properties = d + return schedules_get_response_owner + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_list_content_type.py b/omni_python_sdk/models/schedules_list_content_type.py new file mode 100644 index 0000000..6e680b9 --- /dev/null +++ b/omni_python_sdk/models/schedules_list_content_type.py @@ -0,0 +1,14 @@ +from typing import Literal + +SchedulesListContentType = Literal["dashboard", "single tile"] + +SCHEDULES_LIST_CONTENT_TYPE_VALUES: set[SchedulesListContentType] = { + "dashboard", + "single tile", +} + + +def check_schedules_list_content_type(value: str) -> SchedulesListContentType: + if value in SCHEDULES_LIST_CONTENT_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SCHEDULES_LIST_CONTENT_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/schedules_list_destination.py b/omni_python_sdk/models/schedules_list_destination.py new file mode 100644 index 0000000..ccfdfbb --- /dev/null +++ b/omni_python_sdk/models/schedules_list_destination.py @@ -0,0 +1,18 @@ +from typing import Literal + +SchedulesListDestination = Literal["email", "google_sheets", "s3", "sftp", "slack", "webhook"] + +SCHEDULES_LIST_DESTINATION_VALUES: set[SchedulesListDestination] = { + "email", + "google_sheets", + "s3", + "sftp", + "slack", + "webhook", +} + + +def check_schedules_list_destination(value: str) -> SchedulesListDestination: + if value in SCHEDULES_LIST_DESTINATION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SCHEDULES_LIST_DESTINATION_VALUES!r}") diff --git a/omni_python_sdk/models/schedules_list_item.py b/omni_python_sdk/models/schedules_list_item.py new file mode 100644 index 0000000..b0d0ccd --- /dev/null +++ b/omni_python_sdk/models/schedules_list_item.py @@ -0,0 +1,296 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.schedules_list_item_alert import SchedulesListItemAlert + + +T = TypeVar("T", bound="SchedulesListItem") + + +@_attrs_define +class SchedulesListItem: + """ + Attributes: + content (str): Content type: dashboard or tile Example: dashboard. + dashboard_name (str): Name of the dashboard Example: Weekly Sales Report. + destination_type (str): Delivery destination type: email, slack, webhook, sftp, s3, google_sheets Example: + email. + disabled_at (datetime.datetime | None): Timestamp when the schedule was paused (null if active) + format_ (str): Output format: pdf, png, csv, xlsx, json, link_only Example: pdf. + id (UUID): Unique identifier for the schedule + identifier (str): Dashboard identifier Example: 12db1a0a. + last_completed_at (datetime.datetime | None): Timestamp of last completed delivery + last_status (None | str): Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET + name (str): Name of the schedule Example: Weekly Sales Report. + owner_id (UUID): User ID of the schedule owner + owner_name (str): Display name of the schedule owner Example: John Doe. + recipient_count (float): Number of recipients (-1 for non-email destinations) Example: 5. + schedule (str): AWS EventBridge cron expression (minute hour day-of-month month day-of-week year) Example: 0 9 ? + * MON *. + slack_recipient_type (None | str): Slack recipient type: Channel or Users (null for non-Slack) + system_disabled_at (datetime.datetime | None): Timestamp when system disabled the schedule (null if not system- + disabled) + system_disabled_reason (None | str): Reason for system disabling: missingQuery, noAccess, + orphanedFilterConfigKeys + timezone (str): IANA timezone for the schedule Example: America/New_York. + alert (SchedulesListItemAlert | Unset): Alert configuration (only present for alert-type schedules) + """ + + content: str + dashboard_name: str + destination_type: str + disabled_at: datetime.datetime | None + format_: str + id: UUID + identifier: str + last_completed_at: datetime.datetime | None + last_status: None | str + name: str + owner_id: UUID + owner_name: str + recipient_count: float + schedule: str + slack_recipient_type: None | str + system_disabled_at: datetime.datetime | None + system_disabled_reason: None | str + timezone: str + alert: SchedulesListItemAlert | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + content = self.content + + dashboard_name = self.dashboard_name + + destination_type = self.destination_type + + disabled_at: None | str + if isinstance(self.disabled_at, datetime.datetime): + disabled_at = self.disabled_at.isoformat() + else: + disabled_at = self.disabled_at + + format_ = self.format_ + + id = str(self.id) + + identifier = self.identifier + + last_completed_at: None | str + if isinstance(self.last_completed_at, datetime.datetime): + last_completed_at = self.last_completed_at.isoformat() + else: + last_completed_at = self.last_completed_at + + last_status: None | str + last_status = self.last_status + + name = self.name + + owner_id = str(self.owner_id) + + owner_name = self.owner_name + + recipient_count = self.recipient_count + + schedule = self.schedule + + slack_recipient_type: None | str + slack_recipient_type = self.slack_recipient_type + + system_disabled_at: None | str + if isinstance(self.system_disabled_at, datetime.datetime): + system_disabled_at = self.system_disabled_at.isoformat() + else: + system_disabled_at = self.system_disabled_at + + system_disabled_reason: None | str + system_disabled_reason = self.system_disabled_reason + + timezone = self.timezone + + alert: dict[str, Any] | Unset = UNSET + if not isinstance(self.alert, Unset): + alert = self.alert.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "content": content, + "dashboardName": dashboard_name, + "destinationType": destination_type, + "disabledAt": disabled_at, + "format": format_, + "id": id, + "identifier": identifier, + "lastCompletedAt": last_completed_at, + "lastStatus": last_status, + "name": name, + "ownerId": owner_id, + "ownerName": owner_name, + "recipientCount": recipient_count, + "schedule": schedule, + "slackRecipientType": slack_recipient_type, + "systemDisabledAt": system_disabled_at, + "systemDisabledReason": system_disabled_reason, + "timezone": timezone, + } + ) + if alert is not UNSET: + field_dict["alert"] = alert + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.schedules_list_item_alert import SchedulesListItemAlert + + d = dict(src_dict) + content = d.pop("content") + + dashboard_name = d.pop("dashboardName") + + destination_type = d.pop("destinationType") + + def _parse_disabled_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + disabled_at_type_0 = datetime.datetime.fromisoformat(data) + + return disabled_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + disabled_at = _parse_disabled_at(d.pop("disabledAt")) + + format_ = d.pop("format") + + id = UUID(d.pop("id")) + + identifier = d.pop("identifier") + + def _parse_last_completed_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + last_completed_at_type_0 = datetime.datetime.fromisoformat(data) + + return last_completed_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + last_completed_at = _parse_last_completed_at(d.pop("lastCompletedAt")) + + def _parse_last_status(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + last_status = _parse_last_status(d.pop("lastStatus")) + + name = d.pop("name") + + owner_id = UUID(d.pop("ownerId")) + + owner_name = d.pop("ownerName") + + recipient_count = d.pop("recipientCount") + + schedule = d.pop("schedule") + + def _parse_slack_recipient_type(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + slack_recipient_type = _parse_slack_recipient_type(d.pop("slackRecipientType")) + + def _parse_system_disabled_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + system_disabled_at_type_0 = datetime.datetime.fromisoformat(data) + + return system_disabled_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + system_disabled_at = _parse_system_disabled_at(d.pop("systemDisabledAt")) + + def _parse_system_disabled_reason(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + system_disabled_reason = _parse_system_disabled_reason(d.pop("systemDisabledReason")) + + timezone = d.pop("timezone") + + _alert = d.pop("alert", UNSET) + alert: SchedulesListItemAlert | Unset + if isinstance(_alert, Unset): + alert = UNSET + else: + alert = SchedulesListItemAlert.from_dict(_alert) + + schedules_list_item = cls( + content=content, + dashboard_name=dashboard_name, + destination_type=destination_type, + disabled_at=disabled_at, + format_=format_, + id=id, + identifier=identifier, + last_completed_at=last_completed_at, + last_status=last_status, + name=name, + owner_id=owner_id, + owner_name=owner_name, + recipient_count=recipient_count, + schedule=schedule, + slack_recipient_type=slack_recipient_type, + system_disabled_at=system_disabled_at, + system_disabled_reason=system_disabled_reason, + timezone=timezone, + alert=alert, + ) + + schedules_list_item.additional_properties = d + return schedules_list_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_list_item_alert.py b/omni_python_sdk/models/schedules_list_item_alert.py new file mode 100644 index 0000000..a0f2886 --- /dev/null +++ b/omni_python_sdk/models/schedules_list_item_alert.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SchedulesListItemAlert") + + +@_attrs_define +class SchedulesListItemAlert: + """Alert configuration (only present for alert-type schedules) + + Attributes: + condition_query_name (None | str): Name of the query used for alert condition + condition_type (str): Type of alert condition: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING + """ + + condition_query_name: None | str + condition_type: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + condition_query_name: None | str + condition_query_name = self.condition_query_name + + condition_type = self.condition_type + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "conditionQueryName": condition_query_name, + "conditionType": condition_type, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_condition_query_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + condition_query_name = _parse_condition_query_name(d.pop("conditionQueryName")) + + condition_type = d.pop("conditionType") + + schedules_list_item_alert = cls( + condition_query_name=condition_query_name, + condition_type=condition_type, + ) + + schedules_list_item_alert.additional_properties = d + return schedules_list_item_alert + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_list_response_200.py b/omni_python_sdk/models/schedules_list_response_200.py new file mode 100644 index 0000000..9794f82 --- /dev/null +++ b/omni_python_sdk/models/schedules_list_response_200.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.page_info import PageInfo + from ..models.schedules_list_item import SchedulesListItem + + +T = TypeVar("T", bound="SchedulesListResponse200") + + +@_attrs_define +class SchedulesListResponse200: + """ + Attributes: + page_info (PageInfo): + records (list[SchedulesListItem]): + """ + + page_info: PageInfo + records: list[SchedulesListItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.page_info import PageInfo + from ..models.schedules_list_item import SchedulesListItem + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = SchedulesListItem.from_dict(records_item_data) + + records.append(records_item) + + schedules_list_response_200 = cls( + page_info=page_info, + records=records, + ) + + schedules_list_response_200.additional_properties = d + return schedules_list_response_200 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_list_schedule_type.py b/omni_python_sdk/models/schedules_list_schedule_type.py new file mode 100644 index 0000000..abb7aea --- /dev/null +++ b/omni_python_sdk/models/schedules_list_schedule_type.py @@ -0,0 +1,14 @@ +from typing import Literal + +SchedulesListScheduleType = Literal["alert", "schedule"] + +SCHEDULES_LIST_SCHEDULE_TYPE_VALUES: set[SchedulesListScheduleType] = { + "alert", + "schedule", +} + + +def check_schedules_list_schedule_type(value: str) -> SchedulesListScheduleType: + if value in SCHEDULES_LIST_SCHEDULE_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SCHEDULES_LIST_SCHEDULE_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/schedules_list_sort_direction.py b/omni_python_sdk/models/schedules_list_sort_direction.py new file mode 100644 index 0000000..e6cd707 --- /dev/null +++ b/omni_python_sdk/models/schedules_list_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +SchedulesListSortDirection = Literal["asc", "desc"] + +SCHEDULES_LIST_SORT_DIRECTION_VALUES: set[SchedulesListSortDirection] = { + "asc", + "desc", +} + + +def check_schedules_list_sort_direction(value: str) -> SchedulesListSortDirection: + if value in SCHEDULES_LIST_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SCHEDULES_LIST_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/schedules_list_sort_field.py b/omni_python_sdk/models/schedules_list_sort_field.py new file mode 100644 index 0000000..62d58f3 --- /dev/null +++ b/omni_python_sdk/models/schedules_list_sort_field.py @@ -0,0 +1,17 @@ +from typing import Literal + +SchedulesListSortField = Literal["dashboardName", "lastRun", "lastRunStatus", "ownerName", "scheduleName"] + +SCHEDULES_LIST_SORT_FIELD_VALUES: set[SchedulesListSortField] = { + "dashboardName", + "lastRun", + "lastRunStatus", + "ownerName", + "scheduleName", +} + + +def check_schedules_list_sort_field(value: str) -> SchedulesListSortField: + if value in SCHEDULES_LIST_SORT_FIELD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SCHEDULES_LIST_SORT_FIELD_VALUES!r}") diff --git a/omni_python_sdk/models/schedules_list_status.py b/omni_python_sdk/models/schedules_list_status.py new file mode 100644 index 0000000..7f9cd50 --- /dev/null +++ b/omni_python_sdk/models/schedules_list_status.py @@ -0,0 +1,16 @@ +from typing import Literal + +SchedulesListStatus = Literal["canceled", "error", "none", "success"] + +SCHEDULES_LIST_STATUS_VALUES: set[SchedulesListStatus] = { + "canceled", + "error", + "none", + "success", +} + + +def check_schedules_list_status(value: str) -> SchedulesListStatus: + if value in SCHEDULES_LIST_STATUS_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SCHEDULES_LIST_STATUS_VALUES!r}") diff --git a/omni_python_sdk/models/schedules_recipients_get_response.py b/omni_python_sdk/models/schedules_recipients_get_response.py new file mode 100644 index 0000000..ef98a25 --- /dev/null +++ b/omni_python_sdk/models/schedules_recipients_get_response.py @@ -0,0 +1,118 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.schedules_recipients_get_response_type import ( + SchedulesRecipientsGetResponseType, + check_schedules_recipients_get_response_type, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.email_recipient import EmailRecipient + from ..models.user_group_recipient import UserGroupRecipient + + +T = TypeVar("T", bound="SchedulesRecipientsGetResponse") + + +@_attrs_define +class SchedulesRecipientsGetResponse: + """ + Attributes: + type_ (SchedulesRecipientsGetResponseType): The schedule's destination type. Example: email. + recipients (list[EmailRecipient] | Unset): List of individual recipients (for email destinations). + user_group_recipients (list[UserGroupRecipient] | Unset): List of user group recipients (for email + destinations). + """ + + type_: SchedulesRecipientsGetResponseType + recipients: list[EmailRecipient] | Unset = UNSET + user_group_recipients: list[UserGroupRecipient] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + type_: str = self.type_ + + recipients: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.recipients, Unset): + recipients = [] + for recipients_item_data in self.recipients: + recipients_item = recipients_item_data.to_dict() + recipients.append(recipients_item) + + user_group_recipients: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.user_group_recipients, Unset): + user_group_recipients = [] + for user_group_recipients_item_data in self.user_group_recipients: + user_group_recipients_item = user_group_recipients_item_data.to_dict() + user_group_recipients.append(user_group_recipients_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "type": type_, + } + ) + if recipients is not UNSET: + field_dict["recipients"] = recipients + if user_group_recipients is not UNSET: + field_dict["userGroupRecipients"] = user_group_recipients + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.email_recipient import EmailRecipient + from ..models.user_group_recipient import UserGroupRecipient + + d = dict(src_dict) + type_ = check_schedules_recipients_get_response_type(d.pop("type")) + + _recipients = d.pop("recipients", UNSET) + recipients: list[EmailRecipient] | Unset = UNSET + if _recipients is not UNSET: + recipients = [] + for recipients_item_data in _recipients: + recipients_item = EmailRecipient.from_dict(recipients_item_data) + + recipients.append(recipients_item) + + _user_group_recipients = d.pop("userGroupRecipients", UNSET) + user_group_recipients: list[UserGroupRecipient] | Unset = UNSET + if _user_group_recipients is not UNSET: + user_group_recipients = [] + for user_group_recipients_item_data in _user_group_recipients: + user_group_recipients_item = UserGroupRecipient.from_dict(user_group_recipients_item_data) + + user_group_recipients.append(user_group_recipients_item) + + schedules_recipients_get_response = cls( + type_=type_, + recipients=recipients, + user_group_recipients=user_group_recipients, + ) + + schedules_recipients_get_response.additional_properties = d + return schedules_recipients_get_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_recipients_get_response_type.py b/omni_python_sdk/models/schedules_recipients_get_response_type.py new file mode 100644 index 0000000..7a39369 --- /dev/null +++ b/omni_python_sdk/models/schedules_recipients_get_response_type.py @@ -0,0 +1,18 @@ +from typing import Literal + +SchedulesRecipientsGetResponseType = Literal["email", "google_sheets", "s3", "sftp", "slack", "webhook"] + +SCHEDULES_RECIPIENTS_GET_RESPONSE_TYPE_VALUES: set[SchedulesRecipientsGetResponseType] = { + "email", + "google_sheets", + "s3", + "sftp", + "slack", + "webhook", +} + + +def check_schedules_recipients_get_response_type(value: str) -> SchedulesRecipientsGetResponseType: + if value in SCHEDULES_RECIPIENTS_GET_RESPONSE_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SCHEDULES_RECIPIENTS_GET_RESPONSE_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/schedules_remove_recipients_body.py b/omni_python_sdk/models/schedules_remove_recipients_body.py new file mode 100644 index 0000000..787c4f1 --- /dev/null +++ b/omni_python_sdk/models/schedules_remove_recipients_body.py @@ -0,0 +1,110 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="SchedulesRemoveRecipientsBody") + + +@_attrs_define +class SchedulesRemoveRecipientsBody: + """ + Attributes: + emails (list[str] | Unset): At least one email, userId, or userGroupId must be provided. Array of recipient + email addresses to remove from the scheduled task. Example: ['user@example.com']. + user_group_ids (list[UUID] | Unset): At least one email, userId, or userGroupId must be provided. Array of user + group UUIDs to remove as recipients. Example: ['123e4567-e89b-12d3-a456-426614174000']. + user_ids (list[UUID] | Unset): At least one email, userId, or userGroupId must be provided. Array of recipient + user UUIDs to remove from the scheduled task. Use the List users and List embed users endpoints to retrieve user + IDs. Example: ['987fcdeb-51a2-43d7-9b56-254415f67890']. + """ + + emails: list[str] | Unset = UNSET + user_group_ids: list[UUID] | Unset = UNSET + user_ids: list[UUID] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + emails: list[str] | Unset = UNSET + if not isinstance(self.emails, Unset): + emails = self.emails + + user_group_ids: list[str] | Unset = UNSET + if not isinstance(self.user_group_ids, Unset): + user_group_ids = [] + for user_group_ids_item_data in self.user_group_ids: + user_group_ids_item = str(user_group_ids_item_data) + user_group_ids.append(user_group_ids_item) + + user_ids: list[str] | Unset = UNSET + if not isinstance(self.user_ids, Unset): + user_ids = [] + for user_ids_item_data in self.user_ids: + user_ids_item = str(user_ids_item_data) + user_ids.append(user_ids_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if emails is not UNSET: + field_dict["emails"] = emails + if user_group_ids is not UNSET: + field_dict["userGroupIds"] = user_group_ids + if user_ids is not UNSET: + field_dict["userIds"] = user_ids + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + emails = cast(list[str], d.pop("emails", UNSET)) + + _user_group_ids = d.pop("userGroupIds", UNSET) + user_group_ids: list[UUID] | Unset = UNSET + if _user_group_ids is not UNSET: + user_group_ids = [] + for user_group_ids_item_data in _user_group_ids: + user_group_ids_item = UUID(user_group_ids_item_data) + + user_group_ids.append(user_group_ids_item) + + _user_ids = d.pop("userIds", UNSET) + user_ids: list[UUID] | Unset = UNSET + if _user_ids is not UNSET: + user_ids = [] + for user_ids_item_data in _user_ids: + user_ids_item = UUID(user_ids_item_data) + + user_ids.append(user_ids_item) + + schedules_remove_recipients_body = cls( + emails=emails, + user_group_ids=user_group_ids, + user_ids=user_ids, + ) + + schedules_remove_recipients_body.additional_properties = d + return schedules_remove_recipients_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_remove_recipients_response.py b/omni_python_sdk/models/schedules_remove_recipients_response.py new file mode 100644 index 0000000..2e20087 --- /dev/null +++ b/omni_python_sdk/models/schedules_remove_recipients_response.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SchedulesRemoveRecipientsResponse") + + +@_attrs_define +class SchedulesRemoveRecipientsResponse: + """ + Attributes: + removed_group_recipients_count (float): Number of user group recipients removed. Example: 1. + removed_recipients_count (float): Number of individual recipients removed. Example: 2. + success (bool): Whether the operation was successful. Example: True. + """ + + removed_group_recipients_count: float + removed_recipients_count: float + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + removed_group_recipients_count = self.removed_group_recipients_count + + removed_recipients_count = self.removed_recipients_count + + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "removedGroupRecipientsCount": removed_group_recipients_count, + "removedRecipientsCount": removed_recipients_count, + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + removed_group_recipients_count = d.pop("removedGroupRecipientsCount") + + removed_recipients_count = d.pop("removedRecipientsCount") + + success = d.pop("success") + + schedules_remove_recipients_response = cls( + removed_group_recipients_count=removed_group_recipients_count, + removed_recipients_count=removed_recipients_count, + success=success, + ) + + schedules_remove_recipients_response.additional_properties = d + return schedules_remove_recipients_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/schedules_transfer_ownership_body.py b/omni_python_sdk/models/schedules_transfer_ownership_body.py new file mode 100644 index 0000000..91d2ad0 --- /dev/null +++ b/omni_python_sdk/models/schedules_transfer_ownership_body.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SchedulesTransferOwnershipBody") + + +@_attrs_define +class SchedulesTransferOwnershipBody: + """ + Attributes: + user_id (UUID): The UUID of the user to transfer schedule ownership to. Use the List users endpoint to retrieve + user IDs. The new owner must be a member of the same organization, not be the current owner, and have permission + to view the dashboard associated with the schedule. Example: 987fcdeb-51a2-43d7-9b56-254415f67890. + """ + + user_id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + user_id = str(self.user_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "userId": user_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + user_id = UUID(d.pop("userId")) + + schedules_transfer_ownership_body = cls( + user_id=user_id, + ) + + schedules_transfer_ownership_body.additional_properties = d + return schedules_transfer_ownership_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_group_response.py b/omni_python_sdk/models/scim_group_response.py new file mode 100644 index 0000000..9dab0ec --- /dev/null +++ b/omni_python_sdk/models/scim_group_response.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.scim_group_response_members_item import ScimGroupResponseMembersItem + + +T = TypeVar("T", bound="ScimGroupResponse") + + +@_attrs_define +class ScimGroupResponse: + """ + Attributes: + display_name (str): Group display name + id (str): SCIM group ID (miniUuid) + schemas (list[str]): SCIM schema URIs + members (list[ScimGroupResponseMembersItem] | Unset): Group members + """ + + display_name: str + id: str + schemas: list[str] + members: list[ScimGroupResponseMembersItem] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + display_name = self.display_name + + id = self.id + + schemas = self.schemas + + members: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.members, Unset): + members = [] + for members_item_data in self.members: + members_item = members_item_data.to_dict() + members.append(members_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "displayName": display_name, + "id": id, + "schemas": schemas, + } + ) + if members is not UNSET: + field_dict["members"] = members + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_group_response_members_item import ScimGroupResponseMembersItem + + d = dict(src_dict) + display_name = d.pop("displayName") + + id = d.pop("id") + + schemas = cast(list[str], d.pop("schemas")) + + _members = d.pop("members", UNSET) + members: list[ScimGroupResponseMembersItem] | Unset = UNSET + if _members is not UNSET: + members = [] + for members_item_data in _members: + members_item = ScimGroupResponseMembersItem.from_dict(members_item_data) + + members.append(members_item) + + scim_group_response = cls( + display_name=display_name, + id=id, + schemas=schemas, + members=members, + ) + + scim_group_response.additional_properties = d + return scim_group_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_group_response_members_item.py b/omni_python_sdk/models/scim_group_response_members_item.py new file mode 100644 index 0000000..675b8a6 --- /dev/null +++ b/omni_python_sdk/models/scim_group_response_members_item.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ScimGroupResponseMembersItem") + + +@_attrs_define +class ScimGroupResponseMembersItem: + """ + Attributes: + display (str): Member display name + value (UUID): Member user ID + """ + + display: str + value: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + display = self.display + + value = str(self.value) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "display": display, + "value": value, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + display = d.pop("display") + + value = UUID(d.pop("value")) + + scim_group_response_members_item = cls( + display=display, + value=value, + ) + + scim_group_response_members_item.additional_properties = d + return scim_group_response_members_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_create_body.py b/omni_python_sdk/models/scim_groups_create_body.py new file mode 100644 index 0000000..510ecac --- /dev/null +++ b/omni_python_sdk/models/scim_groups_create_body.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.scim_groups_create_body_members_item import ScimGroupsCreateBodyMembersItem + + +T = TypeVar("T", bound="ScimGroupsCreateBody") + + +@_attrs_define +class ScimGroupsCreateBody: + """ + Attributes: + display_name (str): Display name of the group Example: Engineering Team. + members (list[ScimGroupsCreateBodyMembersItem] | Unset): List of group members + """ + + display_name: str + members: list[ScimGroupsCreateBodyMembersItem] | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + display_name = self.display_name + + members: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.members, Unset): + members = [] + for members_item_data in self.members: + members_item = members_item_data.to_dict() + members.append(members_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "displayName": display_name, + } + ) + if members is not UNSET: + field_dict["members"] = members + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_groups_create_body_members_item import ScimGroupsCreateBodyMembersItem + + d = dict(src_dict) + display_name = d.pop("displayName") + + _members = d.pop("members", UNSET) + members: list[ScimGroupsCreateBodyMembersItem] | Unset = UNSET + if _members is not UNSET: + members = [] + for members_item_data in _members: + members_item = ScimGroupsCreateBodyMembersItem.from_dict(members_item_data) + + members.append(members_item) + + scim_groups_create_body = cls( + display_name=display_name, + members=members, + ) + + scim_groups_create_body.additional_properties = d + return scim_groups_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_create_body_members_item.py b/omni_python_sdk/models/scim_groups_create_body_members_item.py new file mode 100644 index 0000000..cdf06df --- /dev/null +++ b/omni_python_sdk/models/scim_groups_create_body_members_item.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ScimGroupsCreateBodyMembersItem") + + +@_attrs_define +class ScimGroupsCreateBodyMembersItem: + """ + Attributes: + value (UUID): User membership ID Example: 550e8400-e29b-41d4-a716-446655440000. + """ + + value: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + value = str(self.value) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "value": value, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + value = UUID(d.pop("value")) + + scim_groups_create_body_members_item = cls( + value=value, + ) + + scim_groups_create_body_members_item.additional_properties = d + return scim_groups_create_body_members_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_get_excluded_attributes.py b/omni_python_sdk/models/scim_groups_get_excluded_attributes.py new file mode 100644 index 0000000..af556f0 --- /dev/null +++ b/omni_python_sdk/models/scim_groups_get_excluded_attributes.py @@ -0,0 +1,13 @@ +from typing import Literal + +ScimGroupsGetExcludedAttributes = Literal["members"] + +SCIM_GROUPS_GET_EXCLUDED_ATTRIBUTES_VALUES: set[ScimGroupsGetExcludedAttributes] = { + "members", +} + + +def check_scim_groups_get_excluded_attributes(value: str) -> ScimGroupsGetExcludedAttributes: + if value in SCIM_GROUPS_GET_EXCLUDED_ATTRIBUTES_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SCIM_GROUPS_GET_EXCLUDED_ATTRIBUTES_VALUES!r}") diff --git a/omni_python_sdk/models/scim_groups_list_excluded_attributes.py b/omni_python_sdk/models/scim_groups_list_excluded_attributes.py new file mode 100644 index 0000000..26ee68a --- /dev/null +++ b/omni_python_sdk/models/scim_groups_list_excluded_attributes.py @@ -0,0 +1,13 @@ +from typing import Literal + +ScimGroupsListExcludedAttributes = Literal["members"] + +SCIM_GROUPS_LIST_EXCLUDED_ATTRIBUTES_VALUES: set[ScimGroupsListExcludedAttributes] = { + "members", +} + + +def check_scim_groups_list_excluded_attributes(value: str) -> ScimGroupsListExcludedAttributes: + if value in SCIM_GROUPS_LIST_EXCLUDED_ATTRIBUTES_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SCIM_GROUPS_LIST_EXCLUDED_ATTRIBUTES_VALUES!r}") diff --git a/omni_python_sdk/models/scim_groups_list_response.py b/omni_python_sdk/models/scim_groups_list_response.py new file mode 100644 index 0000000..79eb89d --- /dev/null +++ b/omni_python_sdk/models/scim_groups_list_response.py @@ -0,0 +1,107 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.scim_group_response import ScimGroupResponse + + +T = TypeVar("T", bound="ScimGroupsListResponse") + + +@_attrs_define +class ScimGroupsListResponse: + """ + Attributes: + resources (list[ScimGroupResponse]): List of SCIM groups + items_per_page (float): Items per page + schemas (list[str]): SCIM schema URIs + start_index (float): Start index (1-based) + total_results (float): Total number of results + """ + + resources: list[ScimGroupResponse] + items_per_page: float + schemas: list[str] + start_index: float + total_results: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + resources = [] + for resources_item_data in self.resources: + resources_item = resources_item_data.to_dict() + resources.append(resources_item) + + items_per_page = self.items_per_page + + schemas = self.schemas + + start_index = self.start_index + + total_results = self.total_results + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "Resources": resources, + "itemsPerPage": items_per_page, + "schemas": schemas, + "startIndex": start_index, + "totalResults": total_results, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_group_response import ScimGroupResponse + + d = dict(src_dict) + resources = [] + _resources = d.pop("Resources") + for resources_item_data in _resources: + resources_item = ScimGroupResponse.from_dict(resources_item_data) + + resources.append(resources_item) + + items_per_page = d.pop("itemsPerPage") + + schemas = cast(list[str], d.pop("schemas")) + + start_index = d.pop("startIndex") + + total_results = d.pop("totalResults") + + scim_groups_list_response = cls( + resources=resources, + items_per_page=items_per_page, + schemas=schemas, + start_index=start_index, + total_results=total_results, + ) + + scim_groups_list_response.additional_properties = d + return scim_groups_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_patch_body.py b/omni_python_sdk/models/scim_groups_patch_body.py new file mode 100644 index 0000000..341aa74 --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body.py @@ -0,0 +1,160 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.scim_groups_patch_body_schemas_item import ( + ScimGroupsPatchBodySchemasItem, + check_scim_groups_patch_body_schemas_item, +) + +if TYPE_CHECKING: + from ..models.scim_groups_patch_body_operations_item_type_0 import ScimGroupsPatchBodyOperationsItemType0 + from ..models.scim_groups_patch_body_operations_item_type_1 import ScimGroupsPatchBodyOperationsItemType1 + from ..models.scim_groups_patch_body_operations_item_type_2 import ScimGroupsPatchBodyOperationsItemType2 + from ..models.scim_groups_patch_body_operations_item_type_3 import ScimGroupsPatchBodyOperationsItemType3 + + +T = TypeVar("T", bound="ScimGroupsPatchBody") + + +@_attrs_define +class ScimGroupsPatchBody: + """ + Attributes: + operations (list[ScimGroupsPatchBodyOperationsItemType0 | ScimGroupsPatchBodyOperationsItemType1 | + ScimGroupsPatchBodyOperationsItemType2 | ScimGroupsPatchBodyOperationsItemType3]): List of SCIM patch operations + schemas (list[ScimGroupsPatchBodySchemasItem]): SCIM schema URIs + """ + + operations: list[ + ScimGroupsPatchBodyOperationsItemType0 + | ScimGroupsPatchBodyOperationsItemType1 + | ScimGroupsPatchBodyOperationsItemType2 + | ScimGroupsPatchBodyOperationsItemType3 + ] + schemas: list[ScimGroupsPatchBodySchemasItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.scim_groups_patch_body_operations_item_type_0 import ScimGroupsPatchBodyOperationsItemType0 + from ..models.scim_groups_patch_body_operations_item_type_1 import ScimGroupsPatchBodyOperationsItemType1 + from ..models.scim_groups_patch_body_operations_item_type_2 import ScimGroupsPatchBodyOperationsItemType2 + + operations = [] + for operations_item_data in self.operations: + operations_item: dict[str, Any] + if isinstance(operations_item_data, ScimGroupsPatchBodyOperationsItemType0): + operations_item = operations_item_data.to_dict() + elif isinstance(operations_item_data, ScimGroupsPatchBodyOperationsItemType1): + operations_item = operations_item_data.to_dict() + elif isinstance(operations_item_data, ScimGroupsPatchBodyOperationsItemType2): + operations_item = operations_item_data.to_dict() + else: + operations_item = operations_item_data.to_dict() + + operations.append(operations_item) + + schemas = [] + for schemas_item_data in self.schemas: + schemas_item: str = schemas_item_data + schemas.append(schemas_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "Operations": operations, + "schemas": schemas, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_groups_patch_body_operations_item_type_0 import ScimGroupsPatchBodyOperationsItemType0 + from ..models.scim_groups_patch_body_operations_item_type_1 import ScimGroupsPatchBodyOperationsItemType1 + from ..models.scim_groups_patch_body_operations_item_type_2 import ScimGroupsPatchBodyOperationsItemType2 + from ..models.scim_groups_patch_body_operations_item_type_3 import ScimGroupsPatchBodyOperationsItemType3 + + d = dict(src_dict) + operations = [] + _operations = d.pop("Operations") + for operations_item_data in _operations: + + def _parse_operations_item( + data: object, + ) -> ( + ScimGroupsPatchBodyOperationsItemType0 + | ScimGroupsPatchBodyOperationsItemType1 + | ScimGroupsPatchBodyOperationsItemType2 + | ScimGroupsPatchBodyOperationsItemType3 + ): + try: + if not isinstance(data, dict): + raise TypeError() + operations_item_type_0 = ScimGroupsPatchBodyOperationsItemType0.from_dict(data) + + return operations_item_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + operations_item_type_1 = ScimGroupsPatchBodyOperationsItemType1.from_dict(data) + + return operations_item_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + operations_item_type_2 = ScimGroupsPatchBodyOperationsItemType2.from_dict(data) + + return operations_item_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + operations_item_type_3 = ScimGroupsPatchBodyOperationsItemType3.from_dict(data) + + return operations_item_type_3 + + operations_item = _parse_operations_item(operations_item_data) + + operations.append(operations_item) + + schemas = [] + _schemas = d.pop("schemas") + for schemas_item_data in _schemas: + schemas_item = check_scim_groups_patch_body_schemas_item(schemas_item_data) + + schemas.append(schemas_item) + + scim_groups_patch_body = cls( + operations=operations, + schemas=schemas, + ) + + scim_groups_patch_body.additional_properties = d + return scim_groups_patch_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_0.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_0.py new file mode 100644 index 0000000..fc91053 --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_0.py @@ -0,0 +1,82 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.scim_groups_patch_body_operations_item_type_0_op import ( + ScimGroupsPatchBodyOperationsItemType0Op, + check_scim_groups_patch_body_operations_item_type_0_op, +) + +if TYPE_CHECKING: + from ..models.scim_groups_patch_body_operations_item_type_0_value import ScimGroupsPatchBodyOperationsItemType0Value + + +T = TypeVar("T", bound="ScimGroupsPatchBodyOperationsItemType0") + + +@_attrs_define +class ScimGroupsPatchBodyOperationsItemType0: + """ + Attributes: + op (ScimGroupsPatchBodyOperationsItemType0Op): Operation type Example: replace. + value (ScimGroupsPatchBodyOperationsItemType0Value): + """ + + op: ScimGroupsPatchBodyOperationsItemType0Op + value: ScimGroupsPatchBodyOperationsItemType0Value + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + op: str = self.op + + value = self.value.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "op": op, + "value": value, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_groups_patch_body_operations_item_type_0_value import ( + ScimGroupsPatchBodyOperationsItemType0Value, + ) + + d = dict(src_dict) + op = check_scim_groups_patch_body_operations_item_type_0_op(d.pop("op")) + + value = ScimGroupsPatchBodyOperationsItemType0Value.from_dict(d.pop("value")) + + scim_groups_patch_body_operations_item_type_0 = cls( + op=op, + value=value, + ) + + scim_groups_patch_body_operations_item_type_0.additional_properties = d + return scim_groups_patch_body_operations_item_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_0_op.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_0_op.py new file mode 100644 index 0000000..447e9c5 --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_0_op.py @@ -0,0 +1,16 @@ +from typing import Literal + +ScimGroupsPatchBodyOperationsItemType0Op = Literal["Replace", "replace"] + +SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_0_OP_VALUES: set[ScimGroupsPatchBodyOperationsItemType0Op] = { + "Replace", + "replace", +} + + +def check_scim_groups_patch_body_operations_item_type_0_op(value: str) -> ScimGroupsPatchBodyOperationsItemType0Op: + if value in SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_0_OP_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_0_OP_VALUES!r}" + ) diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_0_value.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_0_value.py new file mode 100644 index 0000000..f49b401 --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_0_value.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ScimGroupsPatchBodyOperationsItemType0Value") + + +@_attrs_define +class ScimGroupsPatchBodyOperationsItemType0Value: + """ + Attributes: + display_name (str): New display name Example: Engineering Team. + id (str | Unset): Group ID + """ + + display_name: str + id: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + display_name = self.display_name + + id = self.id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "displayName": display_name, + } + ) + if id is not UNSET: + field_dict["id"] = id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + display_name = d.pop("displayName") + + id = d.pop("id", UNSET) + + scim_groups_patch_body_operations_item_type_0_value = cls( + display_name=display_name, + id=id, + ) + + scim_groups_patch_body_operations_item_type_0_value.additional_properties = d + return scim_groups_patch_body_operations_item_type_0_value + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_1.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_1.py new file mode 100644 index 0000000..b60bb06 --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_1.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.scim_groups_patch_body_operations_item_type_1_op import ( + ScimGroupsPatchBodyOperationsItemType1Op, + check_scim_groups_patch_body_operations_item_type_1_op, +) + +T = TypeVar("T", bound="ScimGroupsPatchBodyOperationsItemType1") + + +@_attrs_define +class ScimGroupsPatchBodyOperationsItemType1: + """ + Attributes: + op (ScimGroupsPatchBodyOperationsItemType1Op): Operation type Example: remove. + path (str): SCIM path for member to remove Example: members[value eq "550e8400-e29b-41d4-a716-446655440000"]. + """ + + op: ScimGroupsPatchBodyOperationsItemType1Op + path: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + op: str = self.op + + path = self.path + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "op": op, + "path": path, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + op = check_scim_groups_patch_body_operations_item_type_1_op(d.pop("op")) + + path = d.pop("path") + + scim_groups_patch_body_operations_item_type_1 = cls( + op=op, + path=path, + ) + + scim_groups_patch_body_operations_item_type_1.additional_properties = d + return scim_groups_patch_body_operations_item_type_1 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_1_op.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_1_op.py new file mode 100644 index 0000000..ab3b592 --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_1_op.py @@ -0,0 +1,16 @@ +from typing import Literal + +ScimGroupsPatchBodyOperationsItemType1Op = Literal["remove", "Remove"] + +SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_1_OP_VALUES: set[ScimGroupsPatchBodyOperationsItemType1Op] = { + "remove", + "Remove", +} + + +def check_scim_groups_patch_body_operations_item_type_1_op(value: str) -> ScimGroupsPatchBodyOperationsItemType1Op: + if value in SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_1_OP_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_1_OP_VALUES!r}" + ) diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2.py new file mode 100644 index 0000000..2376aa0 --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2.py @@ -0,0 +1,104 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.scim_groups_patch_body_operations_item_type_2_op import ( + ScimGroupsPatchBodyOperationsItemType2Op, + check_scim_groups_patch_body_operations_item_type_2_op, +) +from ..models.scim_groups_patch_body_operations_item_type_2_path import ( + ScimGroupsPatchBodyOperationsItemType2Path, + check_scim_groups_patch_body_operations_item_type_2_path, +) + +if TYPE_CHECKING: + from ..models.scim_groups_patch_body_operations_item_type_2_value_item import ( + ScimGroupsPatchBodyOperationsItemType2ValueItem, + ) + + +T = TypeVar("T", bound="ScimGroupsPatchBodyOperationsItemType2") + + +@_attrs_define +class ScimGroupsPatchBodyOperationsItemType2: + """ + Attributes: + op (ScimGroupsPatchBodyOperationsItemType2Op): Operation type Example: add. + path (ScimGroupsPatchBodyOperationsItemType2Path): Path for members Example: members. + value (list[ScimGroupsPatchBodyOperationsItemType2ValueItem]): + """ + + op: ScimGroupsPatchBodyOperationsItemType2Op + path: ScimGroupsPatchBodyOperationsItemType2Path + value: list[ScimGroupsPatchBodyOperationsItemType2ValueItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + op: str = self.op + + path: str = self.path + + value = [] + for value_item_data in self.value: + value_item = value_item_data.to_dict() + value.append(value_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "op": op, + "path": path, + "value": value, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_groups_patch_body_operations_item_type_2_value_item import ( + ScimGroupsPatchBodyOperationsItemType2ValueItem, + ) + + d = dict(src_dict) + op = check_scim_groups_patch_body_operations_item_type_2_op(d.pop("op")) + + path = check_scim_groups_patch_body_operations_item_type_2_path(d.pop("path")) + + value = [] + _value = d.pop("value") + for value_item_data in _value: + value_item = ScimGroupsPatchBodyOperationsItemType2ValueItem.from_dict(value_item_data) + + value.append(value_item) + + scim_groups_patch_body_operations_item_type_2 = cls( + op=op, + path=path, + value=value, + ) + + scim_groups_patch_body_operations_item_type_2.additional_properties = d + return scim_groups_patch_body_operations_item_type_2 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_op.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_op.py new file mode 100644 index 0000000..44a0e7a --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_op.py @@ -0,0 +1,16 @@ +from typing import Literal + +ScimGroupsPatchBodyOperationsItemType2Op = Literal["add", "Add"] + +SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_2_OP_VALUES: set[ScimGroupsPatchBodyOperationsItemType2Op] = { + "add", + "Add", +} + + +def check_scim_groups_patch_body_operations_item_type_2_op(value: str) -> ScimGroupsPatchBodyOperationsItemType2Op: + if value in SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_2_OP_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_2_OP_VALUES!r}" + ) diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_path.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_path.py new file mode 100644 index 0000000..1f59616 --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_path.py @@ -0,0 +1,15 @@ +from typing import Literal + +ScimGroupsPatchBodyOperationsItemType2Path = Literal["members"] + +SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_2_PATH_VALUES: set[ScimGroupsPatchBodyOperationsItemType2Path] = { + "members", +} + + +def check_scim_groups_patch_body_operations_item_type_2_path(value: str) -> ScimGroupsPatchBodyOperationsItemType2Path: + if value in SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_2_PATH_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_2_PATH_VALUES!r}" + ) diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_value_item.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_value_item.py new file mode 100644 index 0000000..d6bbb9e --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_value_item.py @@ -0,0 +1,73 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ScimGroupsPatchBodyOperationsItemType2ValueItem") + + +@_attrs_define +class ScimGroupsPatchBodyOperationsItemType2ValueItem: + """ + Attributes: + value (UUID): User membership ID Example: 550e8400-e29b-41d4-a716-446655440000. + display (str | Unset): Display name of the member Example: john.doe@example.com. + """ + + value: UUID + display: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + value = str(self.value) + + display = self.display + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "value": value, + } + ) + if display is not UNSET: + field_dict["display"] = display + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + value = UUID(d.pop("value")) + + display = d.pop("display", UNSET) + + scim_groups_patch_body_operations_item_type_2_value_item = cls( + value=value, + display=display, + ) + + scim_groups_patch_body_operations_item_type_2_value_item.additional_properties = d + return scim_groups_patch_body_operations_item_type_2_value_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3.py new file mode 100644 index 0000000..d44d5af --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3.py @@ -0,0 +1,122 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.scim_groups_patch_body_operations_item_type_3_op import ( + ScimGroupsPatchBodyOperationsItemType3Op, + check_scim_groups_patch_body_operations_item_type_3_op, +) +from ..models.scim_groups_patch_body_operations_item_type_3_path import ( + ScimGroupsPatchBodyOperationsItemType3Path, + check_scim_groups_patch_body_operations_item_type_3_path, +) + +if TYPE_CHECKING: + from ..models.scim_groups_patch_body_operations_item_type_3_value_type_0_item import ( + ScimGroupsPatchBodyOperationsItemType3ValueType0Item, + ) + + +T = TypeVar("T", bound="ScimGroupsPatchBodyOperationsItemType3") + + +@_attrs_define +class ScimGroupsPatchBodyOperationsItemType3: + """ + Attributes: + op (ScimGroupsPatchBodyOperationsItemType3Op): Operation type Example: replace. + path (ScimGroupsPatchBodyOperationsItemType3Path): Path for attribute to replace Example: members. + value (list[ScimGroupsPatchBodyOperationsItemType3ValueType0Item] | str): + """ + + op: ScimGroupsPatchBodyOperationsItemType3Op + path: ScimGroupsPatchBodyOperationsItemType3Path + value: list[ScimGroupsPatchBodyOperationsItemType3ValueType0Item] | str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + op: str = self.op + + path: str = self.path + + value: list[dict[str, Any]] | str + if isinstance(self.value, list): + value = [] + for value_type_0_item_data in self.value: + value_type_0_item = value_type_0_item_data.to_dict() + value.append(value_type_0_item) + + else: + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "op": op, + "path": path, + "value": value, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_groups_patch_body_operations_item_type_3_value_type_0_item import ( + ScimGroupsPatchBodyOperationsItemType3ValueType0Item, + ) + + d = dict(src_dict) + op = check_scim_groups_patch_body_operations_item_type_3_op(d.pop("op")) + + path = check_scim_groups_patch_body_operations_item_type_3_path(d.pop("path")) + + def _parse_value(data: object) -> list[ScimGroupsPatchBodyOperationsItemType3ValueType0Item] | str: + try: + if not isinstance(data, list): + raise TypeError() + value_type_0 = [] + _value_type_0 = data + for value_type_0_item_data in _value_type_0: + value_type_0_item = ScimGroupsPatchBodyOperationsItemType3ValueType0Item.from_dict( + value_type_0_item_data + ) + + value_type_0.append(value_type_0_item) + + return value_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(list[ScimGroupsPatchBodyOperationsItemType3ValueType0Item] | str, data) + + value = _parse_value(d.pop("value")) + + scim_groups_patch_body_operations_item_type_3 = cls( + op=op, + path=path, + value=value, + ) + + scim_groups_patch_body_operations_item_type_3.additional_properties = d + return scim_groups_patch_body_operations_item_type_3 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3_op.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3_op.py new file mode 100644 index 0000000..66b7fba --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3_op.py @@ -0,0 +1,16 @@ +from typing import Literal + +ScimGroupsPatchBodyOperationsItemType3Op = Literal["Replace", "replace"] + +SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_3_OP_VALUES: set[ScimGroupsPatchBodyOperationsItemType3Op] = { + "Replace", + "replace", +} + + +def check_scim_groups_patch_body_operations_item_type_3_op(value: str) -> ScimGroupsPatchBodyOperationsItemType3Op: + if value in SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_3_OP_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_3_OP_VALUES!r}" + ) diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3_path.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3_path.py new file mode 100644 index 0000000..b0bfe55 --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3_path.py @@ -0,0 +1,16 @@ +from typing import Literal + +ScimGroupsPatchBodyOperationsItemType3Path = Literal["displayName", "members"] + +SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_3_PATH_VALUES: set[ScimGroupsPatchBodyOperationsItemType3Path] = { + "displayName", + "members", +} + + +def check_scim_groups_patch_body_operations_item_type_3_path(value: str) -> ScimGroupsPatchBodyOperationsItemType3Path: + if value in SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_3_PATH_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_3_PATH_VALUES!r}" + ) diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3_value_type_0_item.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3_value_type_0_item.py new file mode 100644 index 0000000..ca4c8dd --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_3_value_type_0_item.py @@ -0,0 +1,73 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="ScimGroupsPatchBodyOperationsItemType3ValueType0Item") + + +@_attrs_define +class ScimGroupsPatchBodyOperationsItemType3ValueType0Item: + """ + Attributes: + value (UUID): User membership ID Example: 550e8400-e29b-41d4-a716-446655440000. + display (str | Unset): Display name of the member Example: john.doe@example.com. + """ + + value: UUID + display: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + value = str(self.value) + + display = self.display + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "value": value, + } + ) + if display is not UNSET: + field_dict["display"] = display + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + value = UUID(d.pop("value")) + + display = d.pop("display", UNSET) + + scim_groups_patch_body_operations_item_type_3_value_type_0_item = cls( + value=value, + display=display, + ) + + scim_groups_patch_body_operations_item_type_3_value_type_0_item.additional_properties = d + return scim_groups_patch_body_operations_item_type_3_value_type_0_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_patch_body_schemas_item.py b/omni_python_sdk/models/scim_groups_patch_body_schemas_item.py new file mode 100644 index 0000000..c62d40b --- /dev/null +++ b/omni_python_sdk/models/scim_groups_patch_body_schemas_item.py @@ -0,0 +1,13 @@ +from typing import Literal + +ScimGroupsPatchBodySchemasItem = Literal["urn:ietf:params:scim:api:messages:2.0:PatchOp"] + +SCIM_GROUPS_PATCH_BODY_SCHEMAS_ITEM_VALUES: set[ScimGroupsPatchBodySchemasItem] = { + "urn:ietf:params:scim:api:messages:2.0:PatchOp", +} + + +def check_scim_groups_patch_body_schemas_item(value: str) -> ScimGroupsPatchBodySchemasItem: + if value in SCIM_GROUPS_PATCH_BODY_SCHEMAS_ITEM_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SCIM_GROUPS_PATCH_BODY_SCHEMAS_ITEM_VALUES!r}") diff --git a/omni_python_sdk/models/scim_groups_replace_body.py b/omni_python_sdk/models/scim_groups_replace_body.py new file mode 100644 index 0000000..cc1e5d4 --- /dev/null +++ b/omni_python_sdk/models/scim_groups_replace_body.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.scim_groups_replace_body_members_item import ScimGroupsReplaceBodyMembersItem + + +T = TypeVar("T", bound="ScimGroupsReplaceBody") + + +@_attrs_define +class ScimGroupsReplaceBody: + """ + Attributes: + display_name (str): Display name of the group Example: Engineering Team. + members (list[ScimGroupsReplaceBodyMembersItem]): List of group members + """ + + display_name: str + members: list[ScimGroupsReplaceBodyMembersItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + display_name = self.display_name + + members = [] + for members_item_data in self.members: + members_item = members_item_data.to_dict() + members.append(members_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "displayName": display_name, + "members": members, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_groups_replace_body_members_item import ScimGroupsReplaceBodyMembersItem + + d = dict(src_dict) + display_name = d.pop("displayName") + + members = [] + _members = d.pop("members") + for members_item_data in _members: + members_item = ScimGroupsReplaceBodyMembersItem.from_dict(members_item_data) + + members.append(members_item) + + scim_groups_replace_body = cls( + display_name=display_name, + members=members, + ) + + scim_groups_replace_body.additional_properties = d + return scim_groups_replace_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_groups_replace_body_members_item.py b/omni_python_sdk/models/scim_groups_replace_body_members_item.py new file mode 100644 index 0000000..f20769d --- /dev/null +++ b/omni_python_sdk/models/scim_groups_replace_body_members_item.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ScimGroupsReplaceBodyMembersItem") + + +@_attrs_define +class ScimGroupsReplaceBodyMembersItem: + """ + Attributes: + display (str): Display name of the member Example: john.doe@example.com. + value (UUID): User membership ID Example: 550e8400-e29b-41d4-a716-446655440000. + """ + + display: str + value: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + display = self.display + + value = str(self.value) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "display": display, + "value": value, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + display = d.pop("display") + + value = UUID(d.pop("value")) + + scim_groups_replace_body_members_item = cls( + display=display, + value=value, + ) + + scim_groups_replace_body_members_item.additional_properties = d + return scim_groups_replace_body_members_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_create_request.py b/omni_python_sdk/models/scim_user_create_request.py new file mode 100644 index 0000000..d2854a9 --- /dev/null +++ b/omni_python_sdk/models/scim_user_create_request.py @@ -0,0 +1,100 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.scim_user_create_request_urnomniparams_10_user_attribute import ( + ScimUserCreateRequestUrnomniparams10UserAttribute, + ) + + +T = TypeVar("T", bound="ScimUserCreateRequest") + + +@_attrs_define +class ScimUserCreateRequest: + """ + Attributes: + display_name (str): Display name of the user Example: John Doe. + user_name (str): Email address (username) of the user Example: user@example.com. + urnomniparams_1_0_user_attribute (ScimUserCreateRequestUrnomniparams10UserAttribute | Unset): Omni user + attributes + """ + + display_name: str + user_name: str + urnomniparams_1_0_user_attribute: ScimUserCreateRequestUrnomniparams10UserAttribute | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + display_name = self.display_name + + user_name = self.user_name + + urnomniparams_1_0_user_attribute: dict[str, Any] | Unset = UNSET + if not isinstance(self.urnomniparams_1_0_user_attribute, Unset): + urnomniparams_1_0_user_attribute = self.urnomniparams_1_0_user_attribute.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "displayName": display_name, + "userName": user_name, + } + ) + if urnomniparams_1_0_user_attribute is not UNSET: + field_dict["urn:omni:params:1.0:UserAttribute"] = urnomniparams_1_0_user_attribute + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_user_create_request_urnomniparams_10_user_attribute import ( + ScimUserCreateRequestUrnomniparams10UserAttribute, + ) + + d = dict(src_dict) + display_name = d.pop("displayName") + + user_name = d.pop("userName") + + _urnomniparams_1_0_user_attribute = d.pop("urn:omni:params:1.0:UserAttribute", UNSET) + urnomniparams_1_0_user_attribute: ScimUserCreateRequestUrnomniparams10UserAttribute | Unset + if isinstance(_urnomniparams_1_0_user_attribute, Unset): + urnomniparams_1_0_user_attribute = UNSET + else: + urnomniparams_1_0_user_attribute = ScimUserCreateRequestUrnomniparams10UserAttribute.from_dict( + _urnomniparams_1_0_user_attribute + ) + + scim_user_create_request = cls( + display_name=display_name, + user_name=user_name, + urnomniparams_1_0_user_attribute=urnomniparams_1_0_user_attribute, + ) + + scim_user_create_request.additional_properties = d + return scim_user_create_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_create_request_urnomniparams_10_user_attribute.py b/omni_python_sdk/models/scim_user_create_request_urnomniparams_10_user_attribute.py new file mode 100644 index 0000000..1138d3b --- /dev/null +++ b/omni_python_sdk/models/scim_user_create_request_urnomniparams_10_user_attribute.py @@ -0,0 +1,156 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.scim_user_create_request_urnomniparams_10_user_attribute_additional_property_type_6 import ( + ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6, + ) + + +T = TypeVar("T", bound="ScimUserCreateRequestUrnomniparams10UserAttribute") + + +@_attrs_define +class ScimUserCreateRequestUrnomniparams10UserAttribute: + """Omni user attributes""" + + additional_properties: dict[ + str, + bool + | float + | list[float] + | list[str] + | None + | ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6 + | str, + ] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.scim_user_create_request_urnomniparams_10_user_attribute_additional_property_type_6 import ( + ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6, + ) + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + if isinstance(prop, list): + field_dict[prop_name] = prop + + elif isinstance(prop, list): + field_dict[prop_name] = prop + + elif isinstance(prop, ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6): + field_dict[prop_name] = prop.to_dict() + else: + field_dict[prop_name] = prop + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_user_create_request_urnomniparams_10_user_attribute_additional_property_type_6 import ( + ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6, + ) + + d = dict(src_dict) + scim_user_create_request_urnomniparams_10_user_attribute = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property( + data: object, + ) -> ( + bool + | float + | list[float] + | list[str] + | None + | ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6 + | str + ): + if data is None: + return data + try: + if not isinstance(data, list): + raise TypeError() + additional_property_type_2 = cast(list[str], data) + + return additional_property_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, list): + raise TypeError() + additional_property_type_3 = cast(list[float], data) + + return additional_property_type_3 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + additional_property_type_6 = ( + ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6.from_dict(data) + ) + + return additional_property_type_6 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast( + bool + | float + | list[float] + | list[str] + | None + | ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6 + | str, + data, + ) + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + scim_user_create_request_urnomniparams_10_user_attribute.additional_properties = additional_properties + return scim_user_create_request_urnomniparams_10_user_attribute + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__( + self, key: str + ) -> ( + bool + | float + | list[float] + | list[str] + | None + | ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6 + | str + ): + return self.additional_properties[key] + + def __setitem__( + self, + key: str, + value: bool + | float + | list[float] + | list[str] + | None + | ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6 + | str, + ) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_create_request_urnomniparams_10_user_attribute_additional_property_type_6.py b/omni_python_sdk/models/scim_user_create_request_urnomniparams_10_user_attribute_additional_property_type_6.py new file mode 100644 index 0000000..0f1e6b0 --- /dev/null +++ b/omni_python_sdk/models/scim_user_create_request_urnomniparams_10_user_attribute_additional_property_type_6.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6") + + +@_attrs_define +class ScimUserCreateRequestUrnomniparams10UserAttributeAdditionalPropertyType6: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + scim_user_create_request_urnomniparams_10_user_attribute_additional_property_type_6 = cls() + + scim_user_create_request_urnomniparams_10_user_attribute_additional_property_type_6.additional_properties = d + return scim_user_create_request_urnomniparams_10_user_attribute_additional_property_type_6 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_patch_request.py b/omni_python_sdk/models/scim_user_patch_request.py new file mode 100644 index 0000000..de483cc --- /dev/null +++ b/omni_python_sdk/models/scim_user_patch_request.py @@ -0,0 +1,96 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.scim_user_patch_request_schemas_item import ( + ScimUserPatchRequestSchemasItem, + check_scim_user_patch_request_schemas_item, +) + +if TYPE_CHECKING: + from ..models.scim_user_patch_request_operations_item import ScimUserPatchRequestOperationsItem + + +T = TypeVar("T", bound="ScimUserPatchRequest") + + +@_attrs_define +class ScimUserPatchRequest: + """ + Attributes: + operations (list[ScimUserPatchRequestOperationsItem]): List of patch operations to apply + schemas (list[ScimUserPatchRequestSchemasItem]): SCIM schema URIs + """ + + operations: list[ScimUserPatchRequestOperationsItem] + schemas: list[ScimUserPatchRequestSchemasItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + operations = [] + for operations_item_data in self.operations: + operations_item = operations_item_data.to_dict() + operations.append(operations_item) + + schemas = [] + for schemas_item_data in self.schemas: + schemas_item: str = schemas_item_data + schemas.append(schemas_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "Operations": operations, + "schemas": schemas, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_user_patch_request_operations_item import ScimUserPatchRequestOperationsItem + + d = dict(src_dict) + operations = [] + _operations = d.pop("Operations") + for operations_item_data in _operations: + operations_item = ScimUserPatchRequestOperationsItem.from_dict(operations_item_data) + + operations.append(operations_item) + + schemas = [] + _schemas = d.pop("schemas") + for schemas_item_data in _schemas: + schemas_item = check_scim_user_patch_request_schemas_item(schemas_item_data) + + schemas.append(schemas_item) + + scim_user_patch_request = cls( + operations=operations, + schemas=schemas, + ) + + scim_user_patch_request.additional_properties = d + return scim_user_patch_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_patch_request_operations_item.py b/omni_python_sdk/models/scim_user_patch_request_operations_item.py new file mode 100644 index 0000000..9e5559f --- /dev/null +++ b/omni_python_sdk/models/scim_user_patch_request_operations_item.py @@ -0,0 +1,141 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.scim_user_patch_request_operations_item_op import ( + ScimUserPatchRequestOperationsItemOp, + check_scim_user_patch_request_operations_item_op, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.scim_user_patch_request_operations_item_value_type_6 import ( + ScimUserPatchRequestOperationsItemValueType6, + ) + + +T = TypeVar("T", bound="ScimUserPatchRequestOperationsItem") + + +@_attrs_define +class ScimUserPatchRequestOperationsItem: + """ + Attributes: + op (ScimUserPatchRequestOperationsItemOp): + value (bool | float | list[float] | list[str] | None | ScimUserPatchRequestOperationsItemValueType6 | str): + path (str | Unset): + """ + + op: ScimUserPatchRequestOperationsItemOp + value: bool | float | list[float] | list[str] | None | ScimUserPatchRequestOperationsItemValueType6 | str + path: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.scim_user_patch_request_operations_item_value_type_6 import ( + ScimUserPatchRequestOperationsItemValueType6, + ) + + op: str = self.op + + value: bool | dict[str, Any] | float | list[float] | list[str] | None | str + if isinstance(self.value, list): + value = self.value + + elif isinstance(self.value, list): + value = self.value + + elif isinstance(self.value, ScimUserPatchRequestOperationsItemValueType6): + value = self.value.to_dict() + else: + value = self.value + + path = self.path + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "op": op, + "value": value, + } + ) + if path is not UNSET: + field_dict["path"] = path + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_user_patch_request_operations_item_value_type_6 import ( + ScimUserPatchRequestOperationsItemValueType6, + ) + + d = dict(src_dict) + op = check_scim_user_patch_request_operations_item_op(d.pop("op")) + + def _parse_value( + data: object, + ) -> bool | float | list[float] | list[str] | None | ScimUserPatchRequestOperationsItemValueType6 | str: + if data is None: + return data + try: + if not isinstance(data, list): + raise TypeError() + value_type_2 = cast(list[str], data) + + return value_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, list): + raise TypeError() + value_type_3 = cast(list[float], data) + + return value_type_3 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + value_type_6 = ScimUserPatchRequestOperationsItemValueType6.from_dict(data) + + return value_type_6 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast( + bool | float | list[float] | list[str] | None | ScimUserPatchRequestOperationsItemValueType6 | str, data + ) + + value = _parse_value(d.pop("value")) + + path = d.pop("path", UNSET) + + scim_user_patch_request_operations_item = cls( + op=op, + value=value, + path=path, + ) + + scim_user_patch_request_operations_item.additional_properties = d + return scim_user_patch_request_operations_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_patch_request_operations_item_op.py b/omni_python_sdk/models/scim_user_patch_request_operations_item_op.py new file mode 100644 index 0000000..e399337 --- /dev/null +++ b/omni_python_sdk/models/scim_user_patch_request_operations_item_op.py @@ -0,0 +1,20 @@ +from typing import Literal + +ScimUserPatchRequestOperationsItemOp = Literal["Add", "add", "Remove", "remove", "Replace", "replace"] + +SCIM_USER_PATCH_REQUEST_OPERATIONS_ITEM_OP_VALUES: set[ScimUserPatchRequestOperationsItemOp] = { + "Add", + "add", + "Remove", + "remove", + "Replace", + "replace", +} + + +def check_scim_user_patch_request_operations_item_op(value: str) -> ScimUserPatchRequestOperationsItemOp: + if value in SCIM_USER_PATCH_REQUEST_OPERATIONS_ITEM_OP_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SCIM_USER_PATCH_REQUEST_OPERATIONS_ITEM_OP_VALUES!r}" + ) diff --git a/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6.py b/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6.py new file mode 100644 index 0000000..d6120b6 --- /dev/null +++ b/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6.py @@ -0,0 +1,151 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user import ( + ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20User, + ) + from ..models.scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute import ( + ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttribute, + ) + + +T = TypeVar("T", bound="ScimUserPatchRequestOperationsItemValueType6") + + +@_attrs_define +class ScimUserPatchRequestOperationsItemValueType6: + """ + Attributes: + urnietfparamsscimschemasextensionenterprise_2_0_user + (ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20User | Unset): + urnomniparams_1_0_user_attribute (ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttribute | + Unset): + active (bool | Unset): + display_name (str | Unset): + user_name (str | Unset): + """ + + urnietfparamsscimschemasextensionenterprise_2_0_user: ( + ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20User | Unset + ) = UNSET + urnomniparams_1_0_user_attribute: ( + ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttribute | Unset + ) = UNSET + active: bool | Unset = UNSET + display_name: str | Unset = UNSET + user_name: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + urnietfparamsscimschemasextensionenterprise_2_0_user: dict[str, Any] | Unset = UNSET + if not isinstance(self.urnietfparamsscimschemasextensionenterprise_2_0_user, Unset): + urnietfparamsscimschemasextensionenterprise_2_0_user = ( + self.urnietfparamsscimschemasextensionenterprise_2_0_user.to_dict() + ) + + urnomniparams_1_0_user_attribute: dict[str, Any] | Unset = UNSET + if not isinstance(self.urnomniparams_1_0_user_attribute, Unset): + urnomniparams_1_0_user_attribute = self.urnomniparams_1_0_user_attribute.to_dict() + + active = self.active + + display_name = self.display_name + + user_name = self.user_name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if urnietfparamsscimschemasextensionenterprise_2_0_user is not UNSET: + field_dict["urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"] = ( + urnietfparamsscimschemasextensionenterprise_2_0_user + ) + if urnomniparams_1_0_user_attribute is not UNSET: + field_dict["urn:omni:params:1.0:UserAttribute"] = urnomniparams_1_0_user_attribute + if active is not UNSET: + field_dict["active"] = active + if display_name is not UNSET: + field_dict["displayName"] = display_name + if user_name is not UNSET: + field_dict["userName"] = user_name + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user import ( + ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20User, + ) + from ..models.scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute import ( + ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttribute, + ) + + d = dict(src_dict) + _urnietfparamsscimschemasextensionenterprise_2_0_user = d.pop( + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", UNSET + ) + urnietfparamsscimschemasextensionenterprise_2_0_user: ( + ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20User | Unset + ) + if isinstance(_urnietfparamsscimschemasextensionenterprise_2_0_user, Unset): + urnietfparamsscimschemasextensionenterprise_2_0_user = UNSET + else: + urnietfparamsscimschemasextensionenterprise_2_0_user = ( + ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20User.from_dict( + _urnietfparamsscimschemasextensionenterprise_2_0_user + ) + ) + + _urnomniparams_1_0_user_attribute = d.pop("urn:omni:params:1.0:UserAttribute", UNSET) + urnomniparams_1_0_user_attribute: ( + ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttribute | Unset + ) + if isinstance(_urnomniparams_1_0_user_attribute, Unset): + urnomniparams_1_0_user_attribute = UNSET + else: + urnomniparams_1_0_user_attribute = ( + ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttribute.from_dict( + _urnomniparams_1_0_user_attribute + ) + ) + + active = d.pop("active", UNSET) + + display_name = d.pop("displayName", UNSET) + + user_name = d.pop("userName", UNSET) + + scim_user_patch_request_operations_item_value_type_6 = cls( + urnietfparamsscimschemasextensionenterprise_2_0_user=urnietfparamsscimschemasextensionenterprise_2_0_user, + urnomniparams_1_0_user_attribute=urnomniparams_1_0_user_attribute, + active=active, + display_name=display_name, + user_name=user_name, + ) + + scim_user_patch_request_operations_item_value_type_6.additional_properties = d + return scim_user_patch_request_operations_item_value_type_6 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user.py b/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user.py new file mode 100644 index 0000000..69c037a --- /dev/null +++ b/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user.py @@ -0,0 +1,159 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6 import ( + ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6, + ) + + +T = TypeVar("T", bound="ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20User") + + +@_attrs_define +class ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20User: + """ """ + + additional_properties: dict[ + str, + bool + | float + | list[float] + | list[str] + | None + | ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6 + | str, + ] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6 import ( + ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6, + ) + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + if isinstance(prop, list): + field_dict[prop_name] = prop + + elif isinstance(prop, list): + field_dict[prop_name] = prop + + elif isinstance( + prop, + ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6, + ): + field_dict[prop_name] = prop.to_dict() + else: + field_dict[prop_name] = prop + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6 import ( + ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6, + ) + + d = dict(src_dict) + scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property( + data: object, + ) -> ( + bool + | float + | list[float] + | list[str] + | None + | ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6 + | str + ): + if data is None: + return data + try: + if not isinstance(data, list): + raise TypeError() + additional_property_type_2 = cast(list[str], data) + + return additional_property_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, list): + raise TypeError() + additional_property_type_3 = cast(list[float], data) + + return additional_property_type_3 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + additional_property_type_6 = ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6.from_dict( + data + ) + + return additional_property_type_6 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast( + bool + | float + | list[float] + | list[str] + | None + | ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6 + | str, + data, + ) + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user.additional_properties = additional_properties + return scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__( + self, key: str + ) -> ( + bool + | float + | list[float] + | list[str] + | None + | ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6 + | str + ): + return self.additional_properties[key] + + def __setitem__( + self, + key: str, + value: bool + | float + | list[float] + | list[str] + | None + | ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6 + | str, + ) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6.py b/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6.py new file mode 100644 index 0000000..e2ab0cb --- /dev/null +++ b/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar( + "T", + bound="ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6", +) + + +@_attrs_define +class ScimUserPatchRequestOperationsItemValueType6Urnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6 = cls() + + scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6.additional_properties = d + return scim_user_patch_request_operations_item_value_type_6_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute.py b/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute.py new file mode 100644 index 0000000..41d77d7 --- /dev/null +++ b/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute.py @@ -0,0 +1,160 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute_additional_property_type_6 import ( + ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6, + ) + + +T = TypeVar("T", bound="ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttribute") + + +@_attrs_define +class ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttribute: + """ """ + + additional_properties: dict[ + str, + bool + | float + | list[float] + | list[str] + | None + | ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6 + | str, + ] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute_additional_property_type_6 import ( + ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6, + ) + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + if isinstance(prop, list): + field_dict[prop_name] = prop + + elif isinstance(prop, list): + field_dict[prop_name] = prop + + elif isinstance( + prop, ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6 + ): + field_dict[prop_name] = prop.to_dict() + else: + field_dict[prop_name] = prop + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute_additional_property_type_6 import ( + ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6, + ) + + d = dict(src_dict) + scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property( + data: object, + ) -> ( + bool + | float + | list[float] + | list[str] + | None + | ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6 + | str + ): + if data is None: + return data + try: + if not isinstance(data, list): + raise TypeError() + additional_property_type_2 = cast(list[str], data) + + return additional_property_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, list): + raise TypeError() + additional_property_type_3 = cast(list[float], data) + + return additional_property_type_3 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + additional_property_type_6 = ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6.from_dict( + data + ) + + return additional_property_type_6 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast( + bool + | float + | list[float] + | list[str] + | None + | ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6 + | str, + data, + ) + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute.additional_properties = ( + additional_properties + ) + return scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__( + self, key: str + ) -> ( + bool + | float + | list[float] + | list[str] + | None + | ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6 + | str + ): + return self.additional_properties[key] + + def __setitem__( + self, + key: str, + value: bool + | float + | list[float] + | list[str] + | None + | ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6 + | str, + ) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute_additional_property_type_6.py b/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute_additional_property_type_6.py new file mode 100644 index 0000000..0e7fc08 --- /dev/null +++ b/omni_python_sdk/models/scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute_additional_property_type_6.py @@ -0,0 +1,49 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar( + "T", bound="ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6" +) + + +@_attrs_define +class ScimUserPatchRequestOperationsItemValueType6Urnomniparams10UserAttributeAdditionalPropertyType6: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute_additional_property_type_6 = cls() + + scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute_additional_property_type_6.additional_properties = d + return scim_user_patch_request_operations_item_value_type_6_urnomniparams_10_user_attribute_additional_property_type_6 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_patch_request_schemas_item.py b/omni_python_sdk/models/scim_user_patch_request_schemas_item.py new file mode 100644 index 0000000..0d0b03b --- /dev/null +++ b/omni_python_sdk/models/scim_user_patch_request_schemas_item.py @@ -0,0 +1,13 @@ +from typing import Literal + +ScimUserPatchRequestSchemasItem = Literal["urn:ietf:params:scim:api:messages:2.0:PatchOp"] + +SCIM_USER_PATCH_REQUEST_SCHEMAS_ITEM_VALUES: set[ScimUserPatchRequestSchemasItem] = { + "urn:ietf:params:scim:api:messages:2.0:PatchOp", +} + + +def check_scim_user_patch_request_schemas_item(value: str) -> ScimUserPatchRequestSchemasItem: + if value in SCIM_USER_PATCH_REQUEST_SCHEMAS_ITEM_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SCIM_USER_PATCH_REQUEST_SCHEMAS_ITEM_VALUES!r}") diff --git a/omni_python_sdk/models/scim_user_put_request.py b/omni_python_sdk/models/scim_user_put_request.py new file mode 100644 index 0000000..cebfdd8 --- /dev/null +++ b/omni_python_sdk/models/scim_user_put_request.py @@ -0,0 +1,146 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user import ( + ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20User, + ) + from ..models.scim_user_put_request_urnomniparams_10_user_attribute import ( + ScimUserPutRequestUrnomniparams10UserAttribute, + ) + + +T = TypeVar("T", bound="ScimUserPutRequest") + + +@_attrs_define +class ScimUserPutRequest: + """ + Attributes: + user_name (str): Email address (username) of the user Example: user@example.com. + active (bool | Unset): Whether the user is active Default: True. + display_name (str | Unset): Display name of the user + urnietfparamsscimschemasextensionenterprise_2_0_user + (ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20User | Unset): Enterprise SCIM user attributes + urnomniparams_1_0_user_attribute (ScimUserPutRequestUrnomniparams10UserAttribute | Unset): Omni user attributes + """ + + user_name: str + active: bool | Unset = True + display_name: str | Unset = UNSET + urnietfparamsscimschemasextensionenterprise_2_0_user: ( + ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20User | Unset + ) = UNSET + urnomniparams_1_0_user_attribute: ScimUserPutRequestUrnomniparams10UserAttribute | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + user_name = self.user_name + + active = self.active + + display_name = self.display_name + + urnietfparamsscimschemasextensionenterprise_2_0_user: dict[str, Any] | Unset = UNSET + if not isinstance(self.urnietfparamsscimschemasextensionenterprise_2_0_user, Unset): + urnietfparamsscimschemasextensionenterprise_2_0_user = ( + self.urnietfparamsscimschemasextensionenterprise_2_0_user.to_dict() + ) + + urnomniparams_1_0_user_attribute: dict[str, Any] | Unset = UNSET + if not isinstance(self.urnomniparams_1_0_user_attribute, Unset): + urnomniparams_1_0_user_attribute = self.urnomniparams_1_0_user_attribute.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "userName": user_name, + } + ) + if active is not UNSET: + field_dict["active"] = active + if display_name is not UNSET: + field_dict["displayName"] = display_name + if urnietfparamsscimschemasextensionenterprise_2_0_user is not UNSET: + field_dict["urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"] = ( + urnietfparamsscimschemasextensionenterprise_2_0_user + ) + if urnomniparams_1_0_user_attribute is not UNSET: + field_dict["urn:omni:params:1.0:UserAttribute"] = urnomniparams_1_0_user_attribute + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user import ( + ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20User, + ) + from ..models.scim_user_put_request_urnomniparams_10_user_attribute import ( + ScimUserPutRequestUrnomniparams10UserAttribute, + ) + + d = dict(src_dict) + user_name = d.pop("userName") + + active = d.pop("active", UNSET) + + display_name = d.pop("displayName", UNSET) + + _urnietfparamsscimschemasextensionenterprise_2_0_user = d.pop( + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User", UNSET + ) + urnietfparamsscimschemasextensionenterprise_2_0_user: ( + ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20User | Unset + ) + if isinstance(_urnietfparamsscimschemasextensionenterprise_2_0_user, Unset): + urnietfparamsscimschemasextensionenterprise_2_0_user = UNSET + else: + urnietfparamsscimschemasextensionenterprise_2_0_user = ( + ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20User.from_dict( + _urnietfparamsscimschemasextensionenterprise_2_0_user + ) + ) + + _urnomniparams_1_0_user_attribute = d.pop("urn:omni:params:1.0:UserAttribute", UNSET) + urnomniparams_1_0_user_attribute: ScimUserPutRequestUrnomniparams10UserAttribute | Unset + if isinstance(_urnomniparams_1_0_user_attribute, Unset): + urnomniparams_1_0_user_attribute = UNSET + else: + urnomniparams_1_0_user_attribute = ScimUserPutRequestUrnomniparams10UserAttribute.from_dict( + _urnomniparams_1_0_user_attribute + ) + + scim_user_put_request = cls( + user_name=user_name, + active=active, + display_name=display_name, + urnietfparamsscimschemasextensionenterprise_2_0_user=urnietfparamsscimschemasextensionenterprise_2_0_user, + urnomniparams_1_0_user_attribute=urnomniparams_1_0_user_attribute, + ) + + scim_user_put_request.additional_properties = d + return scim_user_put_request + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user.py b/omni_python_sdk/models/scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user.py new file mode 100644 index 0000000..2d65f29 --- /dev/null +++ b/omni_python_sdk/models/scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user.py @@ -0,0 +1,160 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6 import ( + ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6, + ) + + +T = TypeVar("T", bound="ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20User") + + +@_attrs_define +class ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20User: + """Enterprise SCIM user attributes""" + + additional_properties: dict[ + str, + bool + | float + | list[float] + | list[str] + | None + | ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6 + | str, + ] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6 import ( + ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6, + ) + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + if isinstance(prop, list): + field_dict[prop_name] = prop + + elif isinstance(prop, list): + field_dict[prop_name] = prop + + elif isinstance( + prop, ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6 + ): + field_dict[prop_name] = prop.to_dict() + else: + field_dict[prop_name] = prop + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6 import ( + ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6, + ) + + d = dict(src_dict) + scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property( + data: object, + ) -> ( + bool + | float + | list[float] + | list[str] + | None + | ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6 + | str + ): + if data is None: + return data + try: + if not isinstance(data, list): + raise TypeError() + additional_property_type_2 = cast(list[str], data) + + return additional_property_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, list): + raise TypeError() + additional_property_type_3 = cast(list[float], data) + + return additional_property_type_3 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + additional_property_type_6 = ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6.from_dict( + data + ) + + return additional_property_type_6 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast( + bool + | float + | list[float] + | list[str] + | None + | ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6 + | str, + data, + ) + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user.additional_properties = ( + additional_properties + ) + return scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__( + self, key: str + ) -> ( + bool + | float + | list[float] + | list[str] + | None + | ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6 + | str + ): + return self.additional_properties[key] + + def __setitem__( + self, + key: str, + value: bool + | float + | list[float] + | list[str] + | None + | ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6 + | str, + ) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6.py b/omni_python_sdk/models/scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6.py new file mode 100644 index 0000000..79a976d --- /dev/null +++ b/omni_python_sdk/models/scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6") + + +@_attrs_define +class ScimUserPutRequestUrnietfparamsscimschemasextensionenterprise20UserAdditionalPropertyType6: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6 = cls() + + scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6.additional_properties = d + return scim_user_put_request_urnietfparamsscimschemasextensionenterprise_20_user_additional_property_type_6 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_put_request_urnomniparams_10_user_attribute.py b/omni_python_sdk/models/scim_user_put_request_urnomniparams_10_user_attribute.py new file mode 100644 index 0000000..eba26cb --- /dev/null +++ b/omni_python_sdk/models/scim_user_put_request_urnomniparams_10_user_attribute.py @@ -0,0 +1,156 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.scim_user_put_request_urnomniparams_10_user_attribute_additional_property_type_6 import ( + ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6, + ) + + +T = TypeVar("T", bound="ScimUserPutRequestUrnomniparams10UserAttribute") + + +@_attrs_define +class ScimUserPutRequestUrnomniparams10UserAttribute: + """Omni user attributes""" + + additional_properties: dict[ + str, + bool + | float + | list[float] + | list[str] + | None + | ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6 + | str, + ] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.scim_user_put_request_urnomniparams_10_user_attribute_additional_property_type_6 import ( + ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6, + ) + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + if isinstance(prop, list): + field_dict[prop_name] = prop + + elif isinstance(prop, list): + field_dict[prop_name] = prop + + elif isinstance(prop, ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6): + field_dict[prop_name] = prop.to_dict() + else: + field_dict[prop_name] = prop + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_user_put_request_urnomniparams_10_user_attribute_additional_property_type_6 import ( + ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6, + ) + + d = dict(src_dict) + scim_user_put_request_urnomniparams_10_user_attribute = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property( + data: object, + ) -> ( + bool + | float + | list[float] + | list[str] + | None + | ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6 + | str + ): + if data is None: + return data + try: + if not isinstance(data, list): + raise TypeError() + additional_property_type_2 = cast(list[str], data) + + return additional_property_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, list): + raise TypeError() + additional_property_type_3 = cast(list[float], data) + + return additional_property_type_3 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, dict): + raise TypeError() + additional_property_type_6 = ( + ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6.from_dict(data) + ) + + return additional_property_type_6 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast( + bool + | float + | list[float] + | list[str] + | None + | ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6 + | str, + data, + ) + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + scim_user_put_request_urnomniparams_10_user_attribute.additional_properties = additional_properties + return scim_user_put_request_urnomniparams_10_user_attribute + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__( + self, key: str + ) -> ( + bool + | float + | list[float] + | list[str] + | None + | ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6 + | str + ): + return self.additional_properties[key] + + def __setitem__( + self, + key: str, + value: bool + | float + | list[float] + | list[str] + | None + | ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6 + | str, + ) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_put_request_urnomniparams_10_user_attribute_additional_property_type_6.py b/omni_python_sdk/models/scim_user_put_request_urnomniparams_10_user_attribute_additional_property_type_6.py new file mode 100644 index 0000000..cac2509 --- /dev/null +++ b/omni_python_sdk/models/scim_user_put_request_urnomniparams_10_user_attribute_additional_property_type_6.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6") + + +@_attrs_define +class ScimUserPutRequestUrnomniparams10UserAttributeAdditionalPropertyType6: + """ """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + scim_user_put_request_urnomniparams_10_user_attribute_additional_property_type_6 = cls() + + scim_user_put_request_urnomniparams_10_user_attribute_additional_property_type_6.additional_properties = d + return scim_user_put_request_urnomniparams_10_user_attribute_additional_property_type_6 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_user_response.py b/omni_python_sdk/models/scim_user_response.py new file mode 100644 index 0000000..93bdf0b --- /dev/null +++ b/omni_python_sdk/models/scim_user_response.py @@ -0,0 +1,94 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="ScimUserResponse") + + +@_attrs_define +class ScimUserResponse: + """ + Attributes: + active (bool): Whether the user is active + display_name (str): Display name + id (UUID): SCIM user ID + schemas (list[str]): SCIM schema URIs + user_name (str): Username (email) + """ + + active: bool + display_name: str + id: UUID + schemas: list[str] + user_name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + active = self.active + + display_name = self.display_name + + id = str(self.id) + + schemas = self.schemas + + user_name = self.user_name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "active": active, + "displayName": display_name, + "id": id, + "schemas": schemas, + "userName": user_name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + active = d.pop("active") + + display_name = d.pop("displayName") + + id = UUID(d.pop("id")) + + schemas = cast(list[str], d.pop("schemas")) + + user_name = d.pop("userName") + + scim_user_response = cls( + active=active, + display_name=display_name, + id=id, + schemas=schemas, + user_name=user_name, + ) + + scim_user_response.additional_properties = d + return scim_user_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/scim_users_list_response.py b/omni_python_sdk/models/scim_users_list_response.py new file mode 100644 index 0000000..04ed533 --- /dev/null +++ b/omni_python_sdk/models/scim_users_list_response.py @@ -0,0 +1,107 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.scim_user_response import ScimUserResponse + + +T = TypeVar("T", bound="ScimUsersListResponse") + + +@_attrs_define +class ScimUsersListResponse: + """ + Attributes: + resources (list[ScimUserResponse]): List of SCIM users + items_per_page (float): Items per page + schemas (list[str]): SCIM schema URIs + start_index (float): Start index (1-based) + total_results (float): Total number of results + """ + + resources: list[ScimUserResponse] + items_per_page: float + schemas: list[str] + start_index: float + total_results: float + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + resources = [] + for resources_item_data in self.resources: + resources_item = resources_item_data.to_dict() + resources.append(resources_item) + + items_per_page = self.items_per_page + + schemas = self.schemas + + start_index = self.start_index + + total_results = self.total_results + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "Resources": resources, + "itemsPerPage": items_per_page, + "schemas": schemas, + "startIndex": start_index, + "totalResults": total_results, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.scim_user_response import ScimUserResponse + + d = dict(src_dict) + resources = [] + _resources = d.pop("Resources") + for resources_item_data in _resources: + resources_item = ScimUserResponse.from_dict(resources_item_data) + + resources.append(resources_item) + + items_per_page = d.pop("itemsPerPage") + + schemas = cast(list[str], d.pop("schemas")) + + start_index = d.pop("startIndex") + + total_results = d.pop("totalResults") + + scim_users_list_response = cls( + resources=resources, + items_per_page=items_per_page, + schemas=schemas, + start_index=start_index, + total_results=total_results, + ) + + scim_users_list_response.additional_properties = d + return scim_users_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/settings_patch_external.py b/omni_python_sdk/models/settings_patch_external.py new file mode 100644 index 0000000..2c0958a --- /dev/null +++ b/omni_python_sdk/models/settings_patch_external.py @@ -0,0 +1,216 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.settings_patch_external_run_queries_on_type_1 import ( + SettingsPatchExternalRunQueriesOnType1, + check_settings_patch_external_run_queries_on_type_1, +) +from ..models.settings_patch_external_run_queries_on_type_2_type_1 import ( + SettingsPatchExternalRunQueriesOnType2Type1, + check_settings_patch_external_run_queries_on_type_2_type_1, +) +from ..models.settings_patch_external_run_queries_on_type_3_type_1 import ( + SettingsPatchExternalRunQueriesOnType3Type1, + check_settings_patch_external_run_queries_on_type_3_type_1, +) +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.settings_patch_external_custom_text_type_0 import SettingsPatchExternalCustomTextType0 + + +T = TypeVar("T", bound="SettingsPatchExternal") + + +@_attrs_define +class SettingsPatchExternal: + """Document settings. Shallow-merged with the existing settings. + + Attributes: + crossfilter_enabled (bool | Unset): When true, clicking a value in one tile filters all other tiles on the + dashboard. + custom_text (None | SettingsPatchExternalCustomTextType0 | Unset): Custom text replacing default UI strings on + the dashboard, e.g. when queries error or return no results. + facet_filters (bool | Unset): When true, dashboard filters are applied per-facet when faceting is active. + refresh_interval (float | None | Unset): Auto-refresh interval in seconds. Null disables auto-refresh. + run_queries_on (None | SettingsPatchExternalRunQueriesOnType1 | SettingsPatchExternalRunQueriesOnType2Type1 | + SettingsPatchExternalRunQueriesOnType3Type1 | Unset): Controls whether dashboard queries execute on the visible + page or across all pages. + """ + + crossfilter_enabled: bool | Unset = UNSET + custom_text: None | SettingsPatchExternalCustomTextType0 | Unset = UNSET + facet_filters: bool | Unset = UNSET + refresh_interval: float | None | Unset = UNSET + run_queries_on: ( + None + | SettingsPatchExternalRunQueriesOnType1 + | SettingsPatchExternalRunQueriesOnType2Type1 + | SettingsPatchExternalRunQueriesOnType3Type1 + | Unset + ) = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.settings_patch_external_custom_text_type_0 import SettingsPatchExternalCustomTextType0 + + crossfilter_enabled = self.crossfilter_enabled + + custom_text: dict[str, Any] | None | Unset + if isinstance(self.custom_text, Unset): + custom_text = UNSET + elif isinstance(self.custom_text, SettingsPatchExternalCustomTextType0): + custom_text = self.custom_text.to_dict() + else: + custom_text = self.custom_text + + facet_filters = self.facet_filters + + refresh_interval: float | None | Unset + if isinstance(self.refresh_interval, Unset): + refresh_interval = UNSET + else: + refresh_interval = self.refresh_interval + + run_queries_on: None | str | Unset + if isinstance(self.run_queries_on, Unset): + run_queries_on = UNSET + elif isinstance(self.run_queries_on, str): + run_queries_on = self.run_queries_on + elif isinstance(self.run_queries_on, str): + run_queries_on = self.run_queries_on + elif isinstance(self.run_queries_on, str): + run_queries_on = self.run_queries_on + else: + run_queries_on = self.run_queries_on + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if crossfilter_enabled is not UNSET: + field_dict["crossfilterEnabled"] = crossfilter_enabled + if custom_text is not UNSET: + field_dict["customText"] = custom_text + if facet_filters is not UNSET: + field_dict["facetFilters"] = facet_filters + if refresh_interval is not UNSET: + field_dict["refreshInterval"] = refresh_interval + if run_queries_on is not UNSET: + field_dict["runQueriesOn"] = run_queries_on + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.settings_patch_external_custom_text_type_0 import SettingsPatchExternalCustomTextType0 + + d = dict(src_dict) + crossfilter_enabled = d.pop("crossfilterEnabled", UNSET) + + def _parse_custom_text(data: object) -> None | SettingsPatchExternalCustomTextType0 | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, dict): + raise TypeError() + custom_text_type_0 = SettingsPatchExternalCustomTextType0.from_dict(data) + + return custom_text_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | SettingsPatchExternalCustomTextType0 | Unset, data) + + custom_text = _parse_custom_text(d.pop("customText", UNSET)) + + facet_filters = d.pop("facetFilters", UNSET) + + def _parse_refresh_interval(data: object) -> float | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(float | None | Unset, data) + + refresh_interval = _parse_refresh_interval(d.pop("refreshInterval", UNSET)) + + def _parse_run_queries_on( + data: object, + ) -> ( + None + | SettingsPatchExternalRunQueriesOnType1 + | SettingsPatchExternalRunQueriesOnType2Type1 + | SettingsPatchExternalRunQueriesOnType3Type1 + | Unset + ): + if data is None: + return data + if isinstance(data, Unset): + return data + try: + if not isinstance(data, str): + raise TypeError() + run_queries_on_type_1 = check_settings_patch_external_run_queries_on_type_1(data) + + return run_queries_on_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, str): + raise TypeError() + run_queries_on_type_2_type_1 = check_settings_patch_external_run_queries_on_type_2_type_1(data) + + return run_queries_on_type_2_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, str): + raise TypeError() + run_queries_on_type_3_type_1 = check_settings_patch_external_run_queries_on_type_3_type_1(data) + + return run_queries_on_type_3_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast( + None + | SettingsPatchExternalRunQueriesOnType1 + | SettingsPatchExternalRunQueriesOnType2Type1 + | SettingsPatchExternalRunQueriesOnType3Type1 + | Unset, + data, + ) + + run_queries_on = _parse_run_queries_on(d.pop("runQueriesOn", UNSET)) + + settings_patch_external = cls( + crossfilter_enabled=crossfilter_enabled, + custom_text=custom_text, + facet_filters=facet_filters, + refresh_interval=refresh_interval, + run_queries_on=run_queries_on, + ) + + settings_patch_external.additional_properties = d + return settings_patch_external + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/settings_patch_external_custom_text_type_0.py b/omni_python_sdk/models/settings_patch_external_custom_text_type_0.py new file mode 100644 index 0000000..42dd572 --- /dev/null +++ b/omni_python_sdk/models/settings_patch_external_custom_text_type_0.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="SettingsPatchExternalCustomTextType0") + + +@_attrs_define +class SettingsPatchExternalCustomTextType0: + """Custom text replacing default UI strings on the dashboard, e.g. when queries error or return no results. + + Attributes: + query_error (str | Unset): Custom text shown when a query errors, replacing the default error text. + query_no_results (str | Unset): Custom text shown when a query returns no results, replacing the default empty + state. + """ + + query_error: str | Unset = UNSET + query_no_results: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + query_error = self.query_error + + query_no_results = self.query_no_results + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if query_error is not UNSET: + field_dict["queryError"] = query_error + if query_no_results is not UNSET: + field_dict["queryNoResults"] = query_no_results + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + query_error = d.pop("queryError", UNSET) + + query_no_results = d.pop("queryNoResults", UNSET) + + settings_patch_external_custom_text_type_0 = cls( + query_error=query_error, + query_no_results=query_no_results, + ) + + settings_patch_external_custom_text_type_0.additional_properties = d + return settings_patch_external_custom_text_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/settings_patch_external_run_queries_on_type_1.py b/omni_python_sdk/models/settings_patch_external_run_queries_on_type_1.py new file mode 100644 index 0000000..bf709a0 --- /dev/null +++ b/omni_python_sdk/models/settings_patch_external_run_queries_on_type_1.py @@ -0,0 +1,16 @@ +from typing import Literal + +SettingsPatchExternalRunQueriesOnType1 = Literal["all-pages", "current-page"] + +SETTINGS_PATCH_EXTERNAL_RUN_QUERIES_ON_TYPE_1_VALUES: set[SettingsPatchExternalRunQueriesOnType1] = { + "all-pages", + "current-page", +} + + +def check_settings_patch_external_run_queries_on_type_1(value: str) -> SettingsPatchExternalRunQueriesOnType1: + if value in SETTINGS_PATCH_EXTERNAL_RUN_QUERIES_ON_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SETTINGS_PATCH_EXTERNAL_RUN_QUERIES_ON_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/settings_patch_external_run_queries_on_type_2_type_1.py b/omni_python_sdk/models/settings_patch_external_run_queries_on_type_2_type_1.py new file mode 100644 index 0000000..547021e --- /dev/null +++ b/omni_python_sdk/models/settings_patch_external_run_queries_on_type_2_type_1.py @@ -0,0 +1,18 @@ +from typing import Literal + +SettingsPatchExternalRunQueriesOnType2Type1 = Literal["all-pages", "current-page"] + +SETTINGS_PATCH_EXTERNAL_RUN_QUERIES_ON_TYPE_2_TYPE_1_VALUES: set[SettingsPatchExternalRunQueriesOnType2Type1] = { + "all-pages", + "current-page", +} + + +def check_settings_patch_external_run_queries_on_type_2_type_1( + value: str, +) -> SettingsPatchExternalRunQueriesOnType2Type1: + if value in SETTINGS_PATCH_EXTERNAL_RUN_QUERIES_ON_TYPE_2_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SETTINGS_PATCH_EXTERNAL_RUN_QUERIES_ON_TYPE_2_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/settings_patch_external_run_queries_on_type_3_type_1.py b/omni_python_sdk/models/settings_patch_external_run_queries_on_type_3_type_1.py new file mode 100644 index 0000000..3df7cef --- /dev/null +++ b/omni_python_sdk/models/settings_patch_external_run_queries_on_type_3_type_1.py @@ -0,0 +1,18 @@ +from typing import Literal + +SettingsPatchExternalRunQueriesOnType3Type1 = Literal["all-pages", "current-page"] + +SETTINGS_PATCH_EXTERNAL_RUN_QUERIES_ON_TYPE_3_TYPE_1_VALUES: set[SettingsPatchExternalRunQueriesOnType3Type1] = { + "all-pages", + "current-page", +} + + +def check_settings_patch_external_run_queries_on_type_3_type_1( + value: str, +) -> SettingsPatchExternalRunQueriesOnType3Type1: + if value in SETTINGS_PATCH_EXTERNAL_RUN_QUERIES_ON_TYPE_3_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SETTINGS_PATCH_EXTERNAL_RUN_QUERIES_ON_TYPE_3_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/settings_read_external.py b/omni_python_sdk/models/settings_read_external.py new file mode 100644 index 0000000..7cd2035 --- /dev/null +++ b/omni_python_sdk/models/settings_read_external.py @@ -0,0 +1,195 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.settings_read_external_run_queries_on_type_1 import ( + SettingsReadExternalRunQueriesOnType1, + check_settings_read_external_run_queries_on_type_1, +) +from ..models.settings_read_external_run_queries_on_type_2_type_1 import ( + SettingsReadExternalRunQueriesOnType2Type1, + check_settings_read_external_run_queries_on_type_2_type_1, +) +from ..models.settings_read_external_run_queries_on_type_3_type_1 import ( + SettingsReadExternalRunQueriesOnType3Type1, + check_settings_read_external_run_queries_on_type_3_type_1, +) + +if TYPE_CHECKING: + from ..models.settings_read_external_custom_text_type_0 import SettingsReadExternalCustomTextType0 + + +T = TypeVar("T", bound="SettingsReadExternal") + + +@_attrs_define +class SettingsReadExternal: + """ + Attributes: + crossfilter_enabled (bool): When true, clicking a value in one tile filters all other tiles on the dashboard. + custom_text (None | SettingsReadExternalCustomTextType0): Custom text replacing default UI strings on the + dashboard, e.g. when queries error or return no results. + facet_filters (bool): When true, dashboard filters are applied per-facet when faceting is active. + refresh_interval (float | None): Auto-refresh interval in seconds. Null disables auto-refresh. + run_queries_on (None | SettingsReadExternalRunQueriesOnType1 | SettingsReadExternalRunQueriesOnType2Type1 | + SettingsReadExternalRunQueriesOnType3Type1): Controls whether dashboard queries execute on the visible page or + across all pages. + """ + + crossfilter_enabled: bool + custom_text: None | SettingsReadExternalCustomTextType0 + facet_filters: bool + refresh_interval: float | None + run_queries_on: ( + None + | SettingsReadExternalRunQueriesOnType1 + | SettingsReadExternalRunQueriesOnType2Type1 + | SettingsReadExternalRunQueriesOnType3Type1 + ) + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.settings_read_external_custom_text_type_0 import SettingsReadExternalCustomTextType0 + + crossfilter_enabled = self.crossfilter_enabled + + custom_text: dict[str, Any] | None + if isinstance(self.custom_text, SettingsReadExternalCustomTextType0): + custom_text = self.custom_text.to_dict() + else: + custom_text = self.custom_text + + facet_filters = self.facet_filters + + refresh_interval: float | None + refresh_interval = self.refresh_interval + + run_queries_on: None | str + if isinstance(self.run_queries_on, str): + run_queries_on = self.run_queries_on + elif isinstance(self.run_queries_on, str): + run_queries_on = self.run_queries_on + elif isinstance(self.run_queries_on, str): + run_queries_on = self.run_queries_on + else: + run_queries_on = self.run_queries_on + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "crossfilterEnabled": crossfilter_enabled, + "customText": custom_text, + "facetFilters": facet_filters, + "refreshInterval": refresh_interval, + "runQueriesOn": run_queries_on, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.settings_read_external_custom_text_type_0 import SettingsReadExternalCustomTextType0 + + d = dict(src_dict) + crossfilter_enabled = d.pop("crossfilterEnabled") + + def _parse_custom_text(data: object) -> None | SettingsReadExternalCustomTextType0: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + custom_text_type_0 = SettingsReadExternalCustomTextType0.from_dict(data) + + return custom_text_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | SettingsReadExternalCustomTextType0, data) + + custom_text = _parse_custom_text(d.pop("customText")) + + facet_filters = d.pop("facetFilters") + + def _parse_refresh_interval(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + refresh_interval = _parse_refresh_interval(d.pop("refreshInterval")) + + def _parse_run_queries_on( + data: object, + ) -> ( + None + | SettingsReadExternalRunQueriesOnType1 + | SettingsReadExternalRunQueriesOnType2Type1 + | SettingsReadExternalRunQueriesOnType3Type1 + ): + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + run_queries_on_type_1 = check_settings_read_external_run_queries_on_type_1(data) + + return run_queries_on_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, str): + raise TypeError() + run_queries_on_type_2_type_1 = check_settings_read_external_run_queries_on_type_2_type_1(data) + + return run_queries_on_type_2_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + try: + if not isinstance(data, str): + raise TypeError() + run_queries_on_type_3_type_1 = check_settings_read_external_run_queries_on_type_3_type_1(data) + + return run_queries_on_type_3_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast( + None + | SettingsReadExternalRunQueriesOnType1 + | SettingsReadExternalRunQueriesOnType2Type1 + | SettingsReadExternalRunQueriesOnType3Type1, + data, + ) + + run_queries_on = _parse_run_queries_on(d.pop("runQueriesOn")) + + settings_read_external = cls( + crossfilter_enabled=crossfilter_enabled, + custom_text=custom_text, + facet_filters=facet_filters, + refresh_interval=refresh_interval, + run_queries_on=run_queries_on, + ) + + settings_read_external.additional_properties = d + return settings_read_external + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/settings_read_external_custom_text_type_0.py b/omni_python_sdk/models/settings_read_external_custom_text_type_0.py new file mode 100644 index 0000000..15b378f --- /dev/null +++ b/omni_python_sdk/models/settings_read_external_custom_text_type_0.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="SettingsReadExternalCustomTextType0") + + +@_attrs_define +class SettingsReadExternalCustomTextType0: + """Custom text replacing default UI strings on the dashboard, e.g. when queries error or return no results. + + Attributes: + query_error (str | Unset): Custom text shown when a query errors, replacing the default error text. + query_no_results (str | Unset): Custom text shown when a query returns no results, replacing the default empty + state. + """ + + query_error: str | Unset = UNSET + query_no_results: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + query_error = self.query_error + + query_no_results = self.query_no_results + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update({}) + if query_error is not UNSET: + field_dict["queryError"] = query_error + if query_no_results is not UNSET: + field_dict["queryNoResults"] = query_no_results + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + query_error = d.pop("queryError", UNSET) + + query_no_results = d.pop("queryNoResults", UNSET) + + settings_read_external_custom_text_type_0 = cls( + query_error=query_error, + query_no_results=query_no_results, + ) + + settings_read_external_custom_text_type_0.additional_properties = d + return settings_read_external_custom_text_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/settings_read_external_run_queries_on_type_1.py b/omni_python_sdk/models/settings_read_external_run_queries_on_type_1.py new file mode 100644 index 0000000..b7d9ebd --- /dev/null +++ b/omni_python_sdk/models/settings_read_external_run_queries_on_type_1.py @@ -0,0 +1,16 @@ +from typing import Literal + +SettingsReadExternalRunQueriesOnType1 = Literal["all-pages", "current-page"] + +SETTINGS_READ_EXTERNAL_RUN_QUERIES_ON_TYPE_1_VALUES: set[SettingsReadExternalRunQueriesOnType1] = { + "all-pages", + "current-page", +} + + +def check_settings_read_external_run_queries_on_type_1(value: str) -> SettingsReadExternalRunQueriesOnType1: + if value in SETTINGS_READ_EXTERNAL_RUN_QUERIES_ON_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SETTINGS_READ_EXTERNAL_RUN_QUERIES_ON_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/settings_read_external_run_queries_on_type_2_type_1.py b/omni_python_sdk/models/settings_read_external_run_queries_on_type_2_type_1.py new file mode 100644 index 0000000..4d1d4cf --- /dev/null +++ b/omni_python_sdk/models/settings_read_external_run_queries_on_type_2_type_1.py @@ -0,0 +1,16 @@ +from typing import Literal + +SettingsReadExternalRunQueriesOnType2Type1 = Literal["all-pages", "current-page"] + +SETTINGS_READ_EXTERNAL_RUN_QUERIES_ON_TYPE_2_TYPE_1_VALUES: set[SettingsReadExternalRunQueriesOnType2Type1] = { + "all-pages", + "current-page", +} + + +def check_settings_read_external_run_queries_on_type_2_type_1(value: str) -> SettingsReadExternalRunQueriesOnType2Type1: + if value in SETTINGS_READ_EXTERNAL_RUN_QUERIES_ON_TYPE_2_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SETTINGS_READ_EXTERNAL_RUN_QUERIES_ON_TYPE_2_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/settings_read_external_run_queries_on_type_3_type_1.py b/omni_python_sdk/models/settings_read_external_run_queries_on_type_3_type_1.py new file mode 100644 index 0000000..6c8ef5e --- /dev/null +++ b/omni_python_sdk/models/settings_read_external_run_queries_on_type_3_type_1.py @@ -0,0 +1,16 @@ +from typing import Literal + +SettingsReadExternalRunQueriesOnType3Type1 = Literal["all-pages", "current-page"] + +SETTINGS_READ_EXTERNAL_RUN_QUERIES_ON_TYPE_3_TYPE_1_VALUES: set[SettingsReadExternalRunQueriesOnType3Type1] = { + "all-pages", + "current-page", +} + + +def check_settings_read_external_run_queries_on_type_3_type_1(value: str) -> SettingsReadExternalRunQueriesOnType3Type1: + if value in SETTINGS_READ_EXTERNAL_RUN_QUERIES_ON_TYPE_3_TYPE_1_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {SETTINGS_READ_EXTERNAL_RUN_QUERIES_ON_TYPE_3_TYPE_1_VALUES!r}" + ) diff --git a/omni_python_sdk/models/stack_container.py b/omni_python_sdk/models/stack_container.py new file mode 100644 index 0000000..119c1dc --- /dev/null +++ b/omni_python_sdk/models/stack_container.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="StackContainer") + + +@_attrs_define +class StackContainer: + """Stack container — an ordered list of nested children (content, grid, stack, or reference). (Not statically modeled; + use plain dicts.) + + """ + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + stack_container = cls() + + stack_container.additional_properties = d + return stack_container + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/success_response.py b/omni_python_sdk/models/success_response.py new file mode 100644 index 0000000..87a75e0 --- /dev/null +++ b/omni_python_sdk/models/success_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SuccessResponse") + + +@_attrs_define +class SuccessResponse: + """ + Attributes: + success (bool): Whether the operation was successful Example: True. + """ + + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + success = d.pop("success") + + success_response = cls( + success=success, + ) + + success_response.additional_properties = d + return success_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/suggestion_context_edit.py b/omni_python_sdk/models/suggestion_context_edit.py new file mode 100644 index 0000000..8071d44 --- /dev/null +++ b/omni_python_sdk/models/suggestion_context_edit.py @@ -0,0 +1,94 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SuggestionContextEdit") + + +@_attrs_define +class SuggestionContextEdit: + """ + Attributes: + field (str): The model field being edited (e.g. `ai_context`). Example: ai_context. + target (str): Dot-path identifying what the edit applies to, e.g. `views.orders.fields.status`. Example: + views.orders. + value (list[str] | str): The proposed value for the field. + """ + + field: str + target: str + value: list[str] | str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + field = self.field + + target = self.target + + value: list[str] | str + if isinstance(self.value, list): + value = self.value + + else: + value = self.value + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "field": field, + "target": target, + "value": value, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + field = d.pop("field") + + target = d.pop("target") + + def _parse_value(data: object) -> list[str] | str: + try: + if not isinstance(data, list): + raise TypeError() + value_type_1 = cast(list[str], data) + + return value_type_1 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(list[str] | str, data) + + value = _parse_value(d.pop("value")) + + suggestion_context_edit = cls( + field=field, + target=target, + value=value, + ) + + suggestion_context_edit.additional_properties = d + return suggestion_context_edit + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/suggestion_evidence_item.py b/omni_python_sdk/models/suggestion_evidence_item.py new file mode 100644 index 0000000..7734481 --- /dev/null +++ b/omni_python_sdk/models/suggestion_evidence_item.py @@ -0,0 +1,80 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.suggestion_evidence_item_type import SuggestionEvidenceItemType, check_suggestion_evidence_item_type + +T = TypeVar("T", bound="SuggestionEvidenceItem") + + +@_attrs_define +class SuggestionEvidenceItem: + """ + Attributes: + captured_at (str): ISO 8601 timestamp of when the evidence was captured. + chat_ai_session_id (UUID): Chat session that motivated the suggestion. + type_ (SuggestionEvidenceItemType): + """ + + captured_at: str + chat_ai_session_id: UUID + type_: SuggestionEvidenceItemType + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + captured_at = self.captured_at + + chat_ai_session_id = str(self.chat_ai_session_id) + + type_: str = self.type_ + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "capturedAt": captured_at, + "chatAiSessionId": chat_ai_session_id, + "type": type_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + captured_at = d.pop("capturedAt") + + chat_ai_session_id = UUID(d.pop("chatAiSessionId")) + + type_ = check_suggestion_evidence_item_type(d.pop("type")) + + suggestion_evidence_item = cls( + captured_at=captured_at, + chat_ai_session_id=chat_ai_session_id, + type_=type_, + ) + + suggestion_evidence_item.additional_properties = d + return suggestion_evidence_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/suggestion_evidence_item_type.py b/omni_python_sdk/models/suggestion_evidence_item_type.py new file mode 100644 index 0000000..c21ac2d --- /dev/null +++ b/omni_python_sdk/models/suggestion_evidence_item_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +SuggestionEvidenceItemType = Literal["ai_chat"] + +SUGGESTION_EVIDENCE_ITEM_TYPE_VALUES: set[SuggestionEvidenceItemType] = { + "ai_chat", +} + + +def check_suggestion_evidence_item_type(value: str) -> SuggestionEvidenceItemType: + if value in SUGGESTION_EVIDENCE_ITEM_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SUGGESTION_EVIDENCE_ITEM_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/suggestion_proposed_changes.py b/omni_python_sdk/models/suggestion_proposed_changes.py new file mode 100644 index 0000000..40cda0e --- /dev/null +++ b/omni_python_sdk/models/suggestion_proposed_changes.py @@ -0,0 +1,89 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.suggestion_proposed_changes_kind import ( + SuggestionProposedChangesKind, + check_suggestion_proposed_changes_kind, +) + +if TYPE_CHECKING: + from ..models.suggestion_context_edit import SuggestionContextEdit + + +T = TypeVar("T", bound="SuggestionProposedChanges") + + +@_attrs_define +class SuggestionProposedChanges: + """The change(s) the suggestion would apply to the model. + + Attributes: + edits (list[SuggestionContextEdit]): + kind (SuggestionProposedChangesKind): + """ + + edits: list[SuggestionContextEdit] + kind: SuggestionProposedChangesKind + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + edits = [] + for edits_item_data in self.edits: + edits_item = edits_item_data.to_dict() + edits.append(edits_item) + + kind: str = self.kind + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "edits": edits, + "kind": kind, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.suggestion_context_edit import SuggestionContextEdit + + d = dict(src_dict) + edits = [] + _edits = d.pop("edits") + for edits_item_data in _edits: + edits_item = SuggestionContextEdit.from_dict(edits_item_data) + + edits.append(edits_item) + + kind = check_suggestion_proposed_changes_kind(d.pop("kind")) + + suggestion_proposed_changes = cls( + edits=edits, + kind=kind, + ) + + suggestion_proposed_changes.additional_properties = d + return suggestion_proposed_changes + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/suggestion_proposed_changes_kind.py b/omni_python_sdk/models/suggestion_proposed_changes_kind.py new file mode 100644 index 0000000..429b57c --- /dev/null +++ b/omni_python_sdk/models/suggestion_proposed_changes_kind.py @@ -0,0 +1,13 @@ +from typing import Literal + +SuggestionProposedChangesKind = Literal["context_edits"] + +SUGGESTION_PROPOSED_CHANGES_KIND_VALUES: set[SuggestionProposedChangesKind] = { + "context_edits", +} + + +def check_suggestion_proposed_changes_kind(value: str) -> SuggestionProposedChangesKind: + if value in SUGGESTION_PROPOSED_CHANGES_KIND_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SUGGESTION_PROPOSED_CHANGES_KIND_VALUES!r}") diff --git a/omni_python_sdk/models/upload.py b/omni_python_sdk/models/upload.py new file mode 100644 index 0000000..90dfc16 --- /dev/null +++ b/omni_python_sdk/models/upload.py @@ -0,0 +1,190 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.upload_uploaded_by_user_type_0 import UploadUploadedByUserType0 + + +T = TypeVar("T", bound="Upload") + + +@_attrs_define +class Upload: + """ + Attributes: + connection_id (UUID): Connection ID the upload is associated with + created_at (datetime.datetime): When the file was uploaded + file_name (str): Original file name Example: users.csv. + id (UUID): Unique identifier for the upload + in_db_as_table_name (None | str): Database table name if uploaded to database scratch schema + model_id (None | UUID): Model ID the upload is associated with (inferred from connection's shared model if not + explicitly set) + size_bytes (float | None): File size in bytes + updated_at (datetime.datetime): Last update timestamp + uploaded_by_user (None | UploadUploadedByUserType0): User who uploaded the file + view_name (str): View name associated with the upload + """ + + connection_id: UUID + created_at: datetime.datetime + file_name: str + id: UUID + in_db_as_table_name: None | str + model_id: None | UUID + size_bytes: float | None + updated_at: datetime.datetime + uploaded_by_user: None | UploadUploadedByUserType0 + view_name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.upload_uploaded_by_user_type_0 import UploadUploadedByUserType0 + + connection_id = str(self.connection_id) + + created_at = self.created_at.isoformat() + + file_name = self.file_name + + id = str(self.id) + + in_db_as_table_name: None | str + in_db_as_table_name = self.in_db_as_table_name + + model_id: None | str + if isinstance(self.model_id, UUID): + model_id = str(self.model_id) + else: + model_id = self.model_id + + size_bytes: float | None + size_bytes = self.size_bytes + + updated_at = self.updated_at.isoformat() + + uploaded_by_user: dict[str, Any] | None + if isinstance(self.uploaded_by_user, UploadUploadedByUserType0): + uploaded_by_user = self.uploaded_by_user.to_dict() + else: + uploaded_by_user = self.uploaded_by_user + + view_name = self.view_name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "connection_id": connection_id, + "created_at": created_at, + "file_name": file_name, + "id": id, + "in_db_as_table_name": in_db_as_table_name, + "model_id": model_id, + "size_bytes": size_bytes, + "updated_at": updated_at, + "uploaded_by_user": uploaded_by_user, + "view_name": view_name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.upload_uploaded_by_user_type_0 import UploadUploadedByUserType0 + + d = dict(src_dict) + connection_id = UUID(d.pop("connection_id")) + + created_at = datetime.datetime.fromisoformat(d.pop("created_at")) + + file_name = d.pop("file_name") + + id = UUID(d.pop("id")) + + def _parse_in_db_as_table_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + in_db_as_table_name = _parse_in_db_as_table_name(d.pop("in_db_as_table_name")) + + def _parse_model_id(data: object) -> None | UUID: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + model_id_type_0 = UUID(data) + + return model_id_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UUID, data) + + model_id = _parse_model_id(d.pop("model_id")) + + def _parse_size_bytes(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + size_bytes = _parse_size_bytes(d.pop("size_bytes")) + + updated_at = datetime.datetime.fromisoformat(d.pop("updated_at")) + + def _parse_uploaded_by_user(data: object) -> None | UploadUploadedByUserType0: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + uploaded_by_user_type_0 = UploadUploadedByUserType0.from_dict(data) + + return uploaded_by_user_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UploadUploadedByUserType0, data) + + uploaded_by_user = _parse_uploaded_by_user(d.pop("uploaded_by_user")) + + view_name = d.pop("view_name") + + upload = cls( + connection_id=connection_id, + created_at=created_at, + file_name=file_name, + id=id, + in_db_as_table_name=in_db_as_table_name, + model_id=model_id, + size_bytes=size_bytes, + updated_at=updated_at, + uploaded_by_user=uploaded_by_user, + view_name=view_name, + ) + + upload.additional_properties = d + return upload + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/upload_create_body.py b/omni_python_sdk/models/upload_create_body.py new file mode 100644 index 0000000..2cda94e --- /dev/null +++ b/omni_python_sdk/models/upload_create_body.py @@ -0,0 +1,129 @@ +from __future__ import annotations + +from collections.abc import Mapping +from io import BytesIO +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from .. import types +from ..types import UNSET, File, Unset + +T = TypeVar("T", bound="UploadCreateBody") + + +@_attrs_define +class UploadCreateBody: + """ + Attributes: + file (File): The CSV file to upload + model_id (UUID): UUID of the model to create the view in + branch_id (UUID | Unset): UUID of the branch to create the view in (mutually exclusive with branchName) + branch_name (str | Unset): Name of the branch to create the view in (mutually exclusive with branchId) + view_name (str | Unset): Override the view name (defaults to sanitized file name) + """ + + file: File + model_id: UUID + branch_id: UUID | Unset = UNSET + branch_name: str | Unset = UNSET + view_name: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + file = self.file.to_tuple() + + model_id = str(self.model_id) + + branch_id: str | Unset = UNSET + if not isinstance(self.branch_id, Unset): + branch_id = str(self.branch_id) + + branch_name = self.branch_name + + view_name = self.view_name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "file": file, + "modelId": model_id, + } + ) + if branch_id is not UNSET: + field_dict["branchId"] = branch_id + if branch_name is not UNSET: + field_dict["branchName"] = branch_name + if view_name is not UNSET: + field_dict["viewName"] = view_name + + return field_dict + + def to_multipart(self) -> types.RequestFiles: + files: types.RequestFiles = [] + + files.append(("file", self.file.to_tuple())) + + files.append(("modelId", (None, str(self.model_id), "text/plain"))) + + if not isinstance(self.branch_id, Unset): + files.append(("branchId", (None, str(self.branch_id), "text/plain"))) + + if not isinstance(self.branch_name, Unset): + files.append(("branchName", (None, str(self.branch_name).encode(), "text/plain"))) + + if not isinstance(self.view_name, Unset): + files.append(("viewName", (None, str(self.view_name).encode(), "text/plain"))) + + for prop_name, prop in self.additional_properties.items(): + files.append((prop_name, (None, str(prop).encode(), "text/plain"))) + + return files + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + file = File(payload=BytesIO(d.pop("file"))) + + model_id = UUID(d.pop("modelId")) + + _branch_id = d.pop("branchId", UNSET) + branch_id: UUID | Unset + if isinstance(_branch_id, Unset): + branch_id = UNSET + else: + branch_id = UUID(_branch_id) + + branch_name = d.pop("branchName", UNSET) + + view_name = d.pop("viewName", UNSET) + + upload_create_body = cls( + file=file, + model_id=model_id, + branch_id=branch_id, + branch_name=branch_name, + view_name=view_name, + ) + + upload_create_body.additional_properties = d + return upload_create_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/upload_create_response.py b/omni_python_sdk/models/upload_create_response.py new file mode 100644 index 0000000..44b3be7 --- /dev/null +++ b/omni_python_sdk/models/upload_create_response.py @@ -0,0 +1,118 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UploadCreateResponse") + + +@_attrs_define +class UploadCreateResponse: + """ + Attributes: + file_name (str): Original file name Example: users.csv. + id (UUID): Unique identifier for the upload + in_db_as_table_name (str): Database table name in the scratch schema + model_id (UUID): Model ID the view was created in + row_count (int): Number of rows in the uploaded file + truncated (bool): Whether the file was truncated due to row limit + view_created (bool): Whether a view was created in the model + view_name (str): Name of the view created + """ + + file_name: str + id: UUID + in_db_as_table_name: str + model_id: UUID + row_count: int + truncated: bool + view_created: bool + view_name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + file_name = self.file_name + + id = str(self.id) + + in_db_as_table_name = self.in_db_as_table_name + + model_id = str(self.model_id) + + row_count = self.row_count + + truncated = self.truncated + + view_created = self.view_created + + view_name = self.view_name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "fileName": file_name, + "id": id, + "inDbAsTableName": in_db_as_table_name, + "modelId": model_id, + "rowCount": row_count, + "truncated": truncated, + "viewCreated": view_created, + "viewName": view_name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + file_name = d.pop("fileName") + + id = UUID(d.pop("id")) + + in_db_as_table_name = d.pop("inDbAsTableName") + + model_id = UUID(d.pop("modelId")) + + row_count = d.pop("rowCount") + + truncated = d.pop("truncated") + + view_created = d.pop("viewCreated") + + view_name = d.pop("viewName") + + upload_create_response = cls( + file_name=file_name, + id=id, + in_db_as_table_name=in_db_as_table_name, + model_id=model_id, + row_count=row_count, + truncated=truncated, + view_created=view_created, + view_name=view_name, + ) + + upload_create_response.additional_properties = d + return upload_create_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/upload_delete_response.py b/omni_python_sdk/models/upload_delete_response.py new file mode 100644 index 0000000..49fd1e3 --- /dev/null +++ b/omni_python_sdk/models/upload_delete_response.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UploadDeleteResponse") + + +@_attrs_define +class UploadDeleteResponse: + """ + Attributes: + success (bool): Whether the deletion was successful + """ + + success: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + success = self.success + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "success": success, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + success = d.pop("success") + + upload_delete_response = cls( + success=success, + ) + + upload_delete_response.additional_properties = d + return upload_delete_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/upload_uploaded_by_user_type_0.py b/omni_python_sdk/models/upload_uploaded_by_user_type_0.py new file mode 100644 index 0000000..1db0331 --- /dev/null +++ b/omni_python_sdk/models/upload_uploaded_by_user_type_0.py @@ -0,0 +1,71 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UploadUploadedByUserType0") + + +@_attrs_define +class UploadUploadedByUserType0: + """User who uploaded the file + + Attributes: + id (UUID): User ID of the uploader + name (str): Name of the user who uploaded the file + """ + + id: UUID + name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = str(self.id) + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = UUID(d.pop("id")) + + name = d.pop("name") + + upload_uploaded_by_user_type_0 = cls( + id=id, + name=name, + ) + + upload_uploaded_by_user_type_0.additional_properties = d + return upload_uploaded_by_user_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/uploads_list_response.py b/omni_python_sdk/models/uploads_list_response.py new file mode 100644 index 0000000..2ab2ffe --- /dev/null +++ b/omni_python_sdk/models/uploads_list_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.page_info import PageInfo + from ..models.upload import Upload + + +T = TypeVar("T", bound="UploadsListResponse") + + +@_attrs_define +class UploadsListResponse: + """ + Attributes: + page_info (PageInfo): + records (list[Upload]): + """ + + page_info: PageInfo + records: list[Upload] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.page_info import PageInfo + from ..models.upload import Upload + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = Upload.from_dict(records_item_data) + + records.append(records_item) + + uploads_list_response = cls( + page_info=page_info, + records=records, + ) + + uploads_list_response.additional_properties = d + return uploads_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/uploads_list_sort_direction.py b/omni_python_sdk/models/uploads_list_sort_direction.py new file mode 100644 index 0000000..1d6ffa4 --- /dev/null +++ b/omni_python_sdk/models/uploads_list_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +UploadsListSortDirection = Literal["asc", "desc"] + +UPLOADS_LIST_SORT_DIRECTION_VALUES: set[UploadsListSortDirection] = { + "asc", + "desc", +} + + +def check_uploads_list_sort_direction(value: str) -> UploadsListSortDirection: + if value in UPLOADS_LIST_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {UPLOADS_LIST_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/uploads_list_sort_field.py b/omni_python_sdk/models/uploads_list_sort_field.py new file mode 100644 index 0000000..dcc947d --- /dev/null +++ b/omni_python_sdk/models/uploads_list_sort_field.py @@ -0,0 +1,15 @@ +from typing import Literal + +UploadsListSortField = Literal["createdAt", "fileName", "updatedAt"] + +UPLOADS_LIST_SORT_FIELD_VALUES: set[UploadsListSortField] = { + "createdAt", + "fileName", + "updatedAt", +} + + +def check_uploads_list_sort_field(value: str) -> UploadsListSortField: + if value in UPLOADS_LIST_SORT_FIELD_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {UPLOADS_LIST_SORT_FIELD_VALUES!r}") diff --git a/omni_python_sdk/models/uploads_list_type.py b/omni_python_sdk/models/uploads_list_type.py new file mode 100644 index 0000000..d90e663 --- /dev/null +++ b/omni_python_sdk/models/uploads_list_type.py @@ -0,0 +1,14 @@ +from typing import Literal + +UploadsListType = Literal["csv", "spreadsheet"] + +UPLOADS_LIST_TYPE_VALUES: set[UploadsListType] = { + "csv", + "spreadsheet", +} + + +def check_uploads_list_type(value: str) -> UploadsListType: + if value in UPLOADS_LIST_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {UPLOADS_LIST_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/user_attributes_list_response.py b/omni_python_sdk/models/user_attributes_list_response.py new file mode 100644 index 0000000..a103077 --- /dev/null +++ b/omni_python_sdk/models/user_attributes_list_response.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.user_attributes_list_response_records_item import UserAttributesListResponseRecordsItem + + +T = TypeVar("T", bound="UserAttributesListResponse") + + +@_attrs_define +class UserAttributesListResponse: + """ + Attributes: + records (list[UserAttributesListResponseRecordsItem]): All user attribute definitions in the organization, + including both system-defined and custom attributes + """ + + records: list[UserAttributesListResponseRecordsItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.user_attributes_list_response_records_item import UserAttributesListResponseRecordsItem + + d = dict(src_dict) + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = UserAttributesListResponseRecordsItem.from_dict(records_item_data) + + records.append(records_item) + + user_attributes_list_response = cls( + records=records, + ) + + user_attributes_list_response.additional_properties = d + return user_attributes_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/user_attributes_list_response_records_item.py b/omni_python_sdk/models/user_attributes_list_response_records_item.py new file mode 100644 index 0000000..e68c110 --- /dev/null +++ b/omni_python_sdk/models/user_attributes_list_response_records_item.py @@ -0,0 +1,166 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.user_attributes_list_response_records_item_type import ( + UserAttributesListResponseRecordsItemType, + check_user_attributes_list_response_records_item_type, +) + +T = TypeVar("T", bound="UserAttributesListResponseRecordsItem") + + +@_attrs_define +class UserAttributesListResponseRecordsItem: + """ + Attributes: + default_value (float | list[float | str] | None | str): Default value applied when no user-specific value is + set. When multiple_values is true, this is an array. Null if no default is configured. Example: us-east. + description (None | str): Human-readable description of the attribute and its purpose Example: User region for + row-level security filtering. + id (str): Unique identifier for custom attributes. Empty string for system-defined attributes. Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + label (str): Display name shown in the Omni UI Example: Region. + multiple_values (bool): Whether the attribute accepts an array of values. When true, default_value and user- + specific values are arrays. + name (str): Reference name used in model SQL and in embed SSO URL parameters Example: region. + system (bool): System-defined attributes (e.g. omni_user_id, omni_user_email) are built-in and read-only. Custom + attributes have system=false. + type_ (UserAttributesListResponseRecordsItemType): Data type that determines valid values. String attributes + accept text, Number attributes accept numeric values stored as strings for precision. Example: String. + """ + + default_value: float | list[float | str] | None | str + description: None | str + id: str + label: str + multiple_values: bool + name: str + system: bool + type_: UserAttributesListResponseRecordsItemType + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + default_value: float | list[float | str] | None | str + if isinstance(self.default_value, list): + default_value = [] + for default_value_type_2_item_data in self.default_value: + default_value_type_2_item: float | str + default_value_type_2_item = default_value_type_2_item_data + default_value.append(default_value_type_2_item) + + else: + default_value = self.default_value + + description: None | str + description = self.description + + id = self.id + + label = self.label + + multiple_values = self.multiple_values + + name = self.name + + system = self.system + + type_: str = self.type_ + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "default_value": default_value, + "description": description, + "id": id, + "label": label, + "multiple_values": multiple_values, + "name": name, + "system": system, + "type": type_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_default_value(data: object) -> float | list[float | str] | None | str: + if data is None: + return data + try: + if not isinstance(data, list): + raise TypeError() + default_value_type_2 = [] + _default_value_type_2 = data + for default_value_type_2_item_data in _default_value_type_2: + + def _parse_default_value_type_2_item(data: object) -> float | str: + return cast(float | str, data) + + default_value_type_2_item = _parse_default_value_type_2_item(default_value_type_2_item_data) + + default_value_type_2.append(default_value_type_2_item) + + return default_value_type_2 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(float | list[float | str] | None | str, data) + + default_value = _parse_default_value(d.pop("default_value")) + + def _parse_description(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + description = _parse_description(d.pop("description")) + + id = d.pop("id") + + label = d.pop("label") + + multiple_values = d.pop("multiple_values") + + name = d.pop("name") + + system = d.pop("system") + + type_ = check_user_attributes_list_response_records_item_type(d.pop("type")) + + user_attributes_list_response_records_item = cls( + default_value=default_value, + description=description, + id=id, + label=label, + multiple_values=multiple_values, + name=name, + system=system, + type_=type_, + ) + + user_attributes_list_response_records_item.additional_properties = d + return user_attributes_list_response_records_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/user_attributes_list_response_records_item_type.py b/omni_python_sdk/models/user_attributes_list_response_records_item_type.py new file mode 100644 index 0000000..cd67720 --- /dev/null +++ b/omni_python_sdk/models/user_attributes_list_response_records_item_type.py @@ -0,0 +1,16 @@ +from typing import Literal + +UserAttributesListResponseRecordsItemType = Literal["Number", "String"] + +USER_ATTRIBUTES_LIST_RESPONSE_RECORDS_ITEM_TYPE_VALUES: set[UserAttributesListResponseRecordsItemType] = { + "Number", + "String", +} + + +def check_user_attributes_list_response_records_item_type(value: str) -> UserAttributesListResponseRecordsItemType: + if value in USER_ATTRIBUTES_LIST_RESPONSE_RECORDS_ITEM_TYPE_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {USER_ATTRIBUTES_LIST_RESPONSE_RECORDS_ITEM_TYPE_VALUES!r}" + ) diff --git a/omni_python_sdk/models/user_group_recipient.py b/omni_python_sdk/models/user_group_recipient.py new file mode 100644 index 0000000..ceb02b7 --- /dev/null +++ b/omni_python_sdk/models/user_group_recipient.py @@ -0,0 +1,91 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.email_recipient import EmailRecipient + + +T = TypeVar("T", bound="UserGroupRecipient") + + +@_attrs_define +class UserGroupRecipient: + """ + Attributes: + id (str): User group ID. + name (str): User group name. Example: Sales Team. + recipients (list[EmailRecipient]): List of recipients in the user group. + """ + + id: str + name: str + recipients: list[EmailRecipient] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + name = self.name + + recipients = [] + for recipients_item_data in self.recipients: + recipients_item = recipients_item_data.to_dict() + recipients.append(recipients_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "name": name, + "recipients": recipients, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.email_recipient import EmailRecipient + + d = dict(src_dict) + id = d.pop("id") + + name = d.pop("name") + + recipients = [] + _recipients = d.pop("recipients") + for recipients_item_data in _recipients: + recipients_item = EmailRecipient.from_dict(recipients_item_data) + + recipients.append(recipients_item) + + user_group_recipient = cls( + id=id, + name=name, + recipients=recipients, + ) + + user_group_recipient.additional_properties = d + return user_group_recipient + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/user_group_role_assignment_result.py b/omni_python_sdk/models/user_group_role_assignment_result.py new file mode 100644 index 0000000..22970df --- /dev/null +++ b/omni_python_sdk/models/user_group_role_assignment_result.py @@ -0,0 +1,108 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.user_group_role_origin import UserGroupRoleOrigin + + +T = TypeVar("T", bound="UserGroupRoleAssignmentResult") + + +@_attrs_define +class UserGroupRoleAssignmentResult: + """ + Attributes: + base_role (str): The base role definition name Example: VIEWER. + connection_id (UUID): Connection this role applies to + from_ (UserGroupRoleOrigin): Origin of this role assignment + model_id (UUID): Model this role applies to + priority (float): Priority for role resolution (higher = more permissive) + role_name (str): The role name (base or custom) Example: VIEWER. + """ + + base_role: str + connection_id: UUID + from_: UserGroupRoleOrigin + model_id: UUID + priority: float + role_name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + base_role = self.base_role + + connection_id = str(self.connection_id) + + from_ = self.from_.to_dict() + + model_id = str(self.model_id) + + priority = self.priority + + role_name = self.role_name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "baseRole": base_role, + "connectionId": connection_id, + "from": from_, + "modelId": model_id, + "priority": priority, + "roleName": role_name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.user_group_role_origin import UserGroupRoleOrigin + + d = dict(src_dict) + base_role = d.pop("baseRole") + + connection_id = UUID(d.pop("connectionId")) + + from_ = UserGroupRoleOrigin.from_dict(d.pop("from")) + + model_id = UUID(d.pop("modelId")) + + priority = d.pop("priority") + + role_name = d.pop("roleName") + + user_group_role_assignment_result = cls( + base_role=base_role, + connection_id=connection_id, + from_=from_, + model_id=model_id, + priority=priority, + role_name=role_name, + ) + + user_group_role_assignment_result.additional_properties = d + return user_group_role_assignment_result + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/user_group_role_origin.py b/omni_python_sdk/models/user_group_role_origin.py new file mode 100644 index 0000000..ceb7d69 --- /dev/null +++ b/omni_python_sdk/models/user_group_role_origin.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.user_group_role_origin_type import UserGroupRoleOriginType, check_user_group_role_origin_type + +T = TypeVar("T", bound="UserGroupRoleOrigin") + + +@_attrs_define +class UserGroupRoleOrigin: + """Origin of this role assignment + + Attributes: + depth (float): Nesting depth of the group (0 for direct assignment) + mini_uuid (str): Short identifier of the group Example: abc123. + name (str): Name of the group Example: Engineering Team. + type_ (UserGroupRoleOriginType): Role assigned to group + """ + + depth: float + mini_uuid: str + name: str + type_: UserGroupRoleOriginType + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + depth = self.depth + + mini_uuid = self.mini_uuid + + name = self.name + + type_: str = self.type_ + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "depth": depth, + "miniUuid": mini_uuid, + "name": name, + "type": type_, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + depth = d.pop("depth") + + mini_uuid = d.pop("miniUuid") + + name = d.pop("name") + + type_ = check_user_group_role_origin_type(d.pop("type")) + + user_group_role_origin = cls( + depth=depth, + mini_uuid=mini_uuid, + name=name, + type_=type_, + ) + + user_group_role_origin.additional_properties = d + return user_group_role_origin + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/user_group_role_origin_type.py b/omni_python_sdk/models/user_group_role_origin_type.py new file mode 100644 index 0000000..fb28e43 --- /dev/null +++ b/omni_python_sdk/models/user_group_role_origin_type.py @@ -0,0 +1,13 @@ +from typing import Literal + +UserGroupRoleOriginType = Literal["GROUP"] + +USER_GROUP_ROLE_ORIGIN_TYPE_VALUES: set[UserGroupRoleOriginType] = { + "GROUP", +} + + +def check_user_group_role_origin_type(value: str) -> UserGroupRoleOriginType: + if value in USER_GROUP_ROLE_ORIGIN_TYPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {USER_GROUP_ROLE_ORIGIN_TYPE_VALUES!r}") diff --git a/omni_python_sdk/models/user_groups_assign_model_role_body.py b/omni_python_sdk/models/user_groups_assign_model_role_body.py new file mode 100644 index 0000000..020b0be --- /dev/null +++ b/omni_python_sdk/models/user_groups_assign_model_role_body.py @@ -0,0 +1,98 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="UserGroupsAssignModelRoleBody") + + +@_attrs_define +class UserGroupsAssignModelRoleBody: + """ + Attributes: + role_name (str): Name of the role to assign (base or custom role) Example: VIEWER. + connection_id (UUID | Unset): Connection ID for connection-level role assignment. Required if modelId not + provided. Example: 550e8400-e29b-41d4-a716-446655440000. + model_id (UUID | Unset): Model ID for model-level role assignment. Required if connectionId not provided. + Example: 550e8400-e29b-41d4-a716-446655440000. + """ + + role_name: str + connection_id: UUID | Unset = UNSET + model_id: UUID | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + role_name = self.role_name + + connection_id: str | Unset = UNSET + if not isinstance(self.connection_id, Unset): + connection_id = str(self.connection_id) + + model_id: str | Unset = UNSET + if not isinstance(self.model_id, Unset): + model_id = str(self.model_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "roleName": role_name, + } + ) + if connection_id is not UNSET: + field_dict["connectionId"] = connection_id + if model_id is not UNSET: + field_dict["modelId"] = model_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + role_name = d.pop("roleName") + + _connection_id = d.pop("connectionId", UNSET) + connection_id: UUID | Unset + if isinstance(_connection_id, Unset): + connection_id = UNSET + else: + connection_id = UUID(_connection_id) + + _model_id = d.pop("modelId", UNSET) + model_id: UUID | Unset + if isinstance(_model_id, Unset): + model_id = UNSET + else: + model_id = UUID(_model_id) + + user_groups_assign_model_role_body = cls( + role_name=role_name, + connection_id=connection_id, + model_id=model_id, + ) + + user_groups_assign_model_role_body.additional_properties = d + return user_groups_assign_model_role_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/user_groups_assign_model_role_response.py b/omni_python_sdk/models/user_groups_assign_model_role_response.py new file mode 100644 index 0000000..a13f8ef --- /dev/null +++ b/omni_python_sdk/models/user_groups_assign_model_role_response.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UserGroupsAssignModelRoleResponse") + + +@_attrs_define +class UserGroupsAssignModelRoleResponse: + """ + Attributes: + connection_id (UUID): The connection ID for this role assignment + model_id (UUID): The model ID for this role assignment + role_name (str): The assigned role name Example: VIEWER. + user_group_id (str): The user group short identifier Example: abc123. + """ + + connection_id: UUID + model_id: UUID + role_name: str + user_group_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + connection_id = str(self.connection_id) + + model_id = str(self.model_id) + + role_name = self.role_name + + user_group_id = self.user_group_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "connectionId": connection_id, + "modelId": model_id, + "roleName": role_name, + "userGroupId": user_group_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + connection_id = UUID(d.pop("connectionId")) + + model_id = UUID(d.pop("modelId")) + + role_name = d.pop("roleName") + + user_group_id = d.pop("userGroupId") + + user_groups_assign_model_role_response = cls( + connection_id=connection_id, + model_id=model_id, + role_name=role_name, + user_group_id=user_group_id, + ) + + user_groups_assign_model_role_response.additional_properties = d + return user_groups_assign_model_role_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/user_groups_get_model_roles_response.py b/omni_python_sdk/models/user_groups_get_model_roles_response.py new file mode 100644 index 0000000..a5c14a1 --- /dev/null +++ b/omni_python_sdk/models/user_groups_get_model_roles_response.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.user_group_role_assignment_result import UserGroupRoleAssignmentResult + + +T = TypeVar("T", bound="UserGroupsGetModelRolesResponse") + + +@_attrs_define +class UserGroupsGetModelRolesResponse: + """ + Attributes: + results (list[UserGroupRoleAssignmentResult]): List of role assignments + user_group_id (str): The user group short identifier Example: abc123. + """ + + results: list[UserGroupRoleAssignmentResult] + user_group_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + results = [] + for results_item_data in self.results: + results_item = results_item_data.to_dict() + results.append(results_item) + + user_group_id = self.user_group_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "results": results, + "userGroupId": user_group_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.user_group_role_assignment_result import UserGroupRoleAssignmentResult + + d = dict(src_dict) + results = [] + _results = d.pop("results") + for results_item_data in _results: + results_item = UserGroupRoleAssignmentResult.from_dict(results_item_data) + + results.append(results_item) + + user_group_id = d.pop("userGroupId") + + user_groups_get_model_roles_response = cls( + results=results, + user_group_id=user_group_id, + ) + + user_groups_get_model_roles_response.additional_properties = d + return user_groups_get_model_roles_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_assign_model_role_body.py b/omni_python_sdk/models/users_assign_model_role_body.py new file mode 100644 index 0000000..592ec0d --- /dev/null +++ b/omni_python_sdk/models/users_assign_model_role_body.py @@ -0,0 +1,98 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="UsersAssignModelRoleBody") + + +@_attrs_define +class UsersAssignModelRoleBody: + """ + Attributes: + role_name (str): Name of the role to assign (base or custom role) Example: VIEWER. + connection_id (UUID | Unset): Connection ID for connection-level role assignment. Required if modelId not + provided. Example: 550e8400-e29b-41d4-a716-446655440000. + model_id (UUID | Unset): Model ID for model-level role assignment. Required if connectionId not provided. + Example: 550e8400-e29b-41d4-a716-446655440000. + """ + + role_name: str + connection_id: UUID | Unset = UNSET + model_id: UUID | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + role_name = self.role_name + + connection_id: str | Unset = UNSET + if not isinstance(self.connection_id, Unset): + connection_id = str(self.connection_id) + + model_id: str | Unset = UNSET + if not isinstance(self.model_id, Unset): + model_id = str(self.model_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "roleName": role_name, + } + ) + if connection_id is not UNSET: + field_dict["connectionId"] = connection_id + if model_id is not UNSET: + field_dict["modelId"] = model_id + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + role_name = d.pop("roleName") + + _connection_id = d.pop("connectionId", UNSET) + connection_id: UUID | Unset + if isinstance(_connection_id, Unset): + connection_id = UNSET + else: + connection_id = UUID(_connection_id) + + _model_id = d.pop("modelId", UNSET) + model_id: UUID | Unset + if isinstance(_model_id, Unset): + model_id = UNSET + else: + model_id = UUID(_model_id) + + users_assign_model_role_body = cls( + role_name=role_name, + connection_id=connection_id, + model_id=model_id, + ) + + users_assign_model_role_body.additional_properties = d + return users_assign_model_role_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_assign_model_role_response.py b/omni_python_sdk/models/users_assign_model_role_response.py new file mode 100644 index 0000000..1c08983 --- /dev/null +++ b/omni_python_sdk/models/users_assign_model_role_response.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UsersAssignModelRoleResponse") + + +@_attrs_define +class UsersAssignModelRoleResponse: + """ + Attributes: + connection_id (UUID): The connection ID for this role assignment + membership_id (UUID): The user membership ID + model_id (UUID): The model ID for this role assignment + role_name (str): The assigned role name Example: VIEWER. + """ + + connection_id: UUID + membership_id: UUID + model_id: UUID + role_name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + connection_id = str(self.connection_id) + + membership_id = str(self.membership_id) + + model_id = str(self.model_id) + + role_name = self.role_name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "connectionId": connection_id, + "membershipId": membership_id, + "modelId": model_id, + "roleName": role_name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + connection_id = UUID(d.pop("connectionId")) + + membership_id = UUID(d.pop("membershipId")) + + model_id = UUID(d.pop("modelId")) + + role_name = d.pop("roleName") + + users_assign_model_role_response = cls( + connection_id=connection_id, + membership_id=membership_id, + model_id=model_id, + role_name=role_name, + ) + + users_assign_model_role_response.additional_properties = d + return users_assign_model_role_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_create_email_only_body.py b/omni_python_sdk/models/users_create_email_only_body.py new file mode 100644 index 0000000..45c2ce0 --- /dev/null +++ b/omni_python_sdk/models/users_create_email_only_body.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.users_create_email_only_body_user_attributes import UsersCreateEmailOnlyBodyUserAttributes + + +T = TypeVar("T", bound="UsersCreateEmailOnlyBody") + + +@_attrs_define +class UsersCreateEmailOnlyBody: + """ + Attributes: + email (str): Email address for the user Example: user@example.com. + user_attributes (UsersCreateEmailOnlyBodyUserAttributes | Unset): Optional user attributes as key-value pairs + """ + + email: str + user_attributes: UsersCreateEmailOnlyBodyUserAttributes | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + email = self.email + + user_attributes: dict[str, Any] | Unset = UNSET + if not isinstance(self.user_attributes, Unset): + user_attributes = self.user_attributes.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "email": email, + } + ) + if user_attributes is not UNSET: + field_dict["userAttributes"] = user_attributes + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.users_create_email_only_body_user_attributes import UsersCreateEmailOnlyBodyUserAttributes + + d = dict(src_dict) + email = d.pop("email") + + _user_attributes = d.pop("userAttributes", UNSET) + user_attributes: UsersCreateEmailOnlyBodyUserAttributes | Unset + if isinstance(_user_attributes, Unset): + user_attributes = UNSET + else: + user_attributes = UsersCreateEmailOnlyBodyUserAttributes.from_dict(_user_attributes) + + users_create_email_only_body = cls( + email=email, + user_attributes=user_attributes, + ) + + users_create_email_only_body.additional_properties = d + return users_create_email_only_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_create_email_only_body_user_attributes.py b/omni_python_sdk/models/users_create_email_only_body_user_attributes.py new file mode 100644 index 0000000..54081fe --- /dev/null +++ b/omni_python_sdk/models/users_create_email_only_body_user_attributes.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UsersCreateEmailOnlyBodyUserAttributes") + + +@_attrs_define +class UsersCreateEmailOnlyBodyUserAttributes: + """Optional user attributes as key-value pairs""" + + additional_properties: dict[str, bool | float | None | str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + users_create_email_only_body_user_attributes = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property(data: object) -> bool | float | None | str: + if data is None: + return data + return cast(bool | float | None | str, data) + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + users_create_email_only_body_user_attributes.additional_properties = additional_properties + return users_create_email_only_body_user_attributes + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> bool | float | None | str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: bool | float | None | str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_create_email_only_bulk_body.py b/omni_python_sdk/models/users_create_email_only_bulk_body.py new file mode 100644 index 0000000..537be2c --- /dev/null +++ b/omni_python_sdk/models/users_create_email_only_bulk_body.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.users_create_email_only_bulk_body_users_item import UsersCreateEmailOnlyBulkBodyUsersItem + + +T = TypeVar("T", bound="UsersCreateEmailOnlyBulkBody") + + +@_attrs_define +class UsersCreateEmailOnlyBulkBody: + """ + Attributes: + users (list[UsersCreateEmailOnlyBulkBodyUsersItem]): Array of users to create (1-20 users) + """ + + users: list[UsersCreateEmailOnlyBulkBodyUsersItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + users = [] + for users_item_data in self.users: + users_item = users_item_data.to_dict() + users.append(users_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "users": users, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.users_create_email_only_bulk_body_users_item import UsersCreateEmailOnlyBulkBodyUsersItem + + d = dict(src_dict) + users = [] + _users = d.pop("users") + for users_item_data in _users: + users_item = UsersCreateEmailOnlyBulkBodyUsersItem.from_dict(users_item_data) + + users.append(users_item) + + users_create_email_only_bulk_body = cls( + users=users, + ) + + users_create_email_only_bulk_body.additional_properties = d + return users_create_email_only_bulk_body + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_create_email_only_bulk_body_users_item.py b/omni_python_sdk/models/users_create_email_only_bulk_body_users_item.py new file mode 100644 index 0000000..bed0bbf --- /dev/null +++ b/omni_python_sdk/models/users_create_email_only_bulk_body_users_item.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.users_create_email_only_bulk_body_users_item_user_attributes import ( + UsersCreateEmailOnlyBulkBodyUsersItemUserAttributes, + ) + + +T = TypeVar("T", bound="UsersCreateEmailOnlyBulkBodyUsersItem") + + +@_attrs_define +class UsersCreateEmailOnlyBulkBodyUsersItem: + """ + Attributes: + email (str): Email address for the user Example: user@example.com. + user_attributes (UsersCreateEmailOnlyBulkBodyUsersItemUserAttributes | Unset): Optional user attributes as key- + value pairs + """ + + email: str + user_attributes: UsersCreateEmailOnlyBulkBodyUsersItemUserAttributes | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + email = self.email + + user_attributes: dict[str, Any] | Unset = UNSET + if not isinstance(self.user_attributes, Unset): + user_attributes = self.user_attributes.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "email": email, + } + ) + if user_attributes is not UNSET: + field_dict["userAttributes"] = user_attributes + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.users_create_email_only_bulk_body_users_item_user_attributes import ( + UsersCreateEmailOnlyBulkBodyUsersItemUserAttributes, + ) + + d = dict(src_dict) + email = d.pop("email") + + _user_attributes = d.pop("userAttributes", UNSET) + user_attributes: UsersCreateEmailOnlyBulkBodyUsersItemUserAttributes | Unset + if isinstance(_user_attributes, Unset): + user_attributes = UNSET + else: + user_attributes = UsersCreateEmailOnlyBulkBodyUsersItemUserAttributes.from_dict(_user_attributes) + + users_create_email_only_bulk_body_users_item = cls( + email=email, + user_attributes=user_attributes, + ) + + users_create_email_only_bulk_body_users_item.additional_properties = d + return users_create_email_only_bulk_body_users_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_create_email_only_bulk_body_users_item_user_attributes.py b/omni_python_sdk/models/users_create_email_only_bulk_body_users_item_user_attributes.py new file mode 100644 index 0000000..7c88ff8 --- /dev/null +++ b/omni_python_sdk/models/users_create_email_only_bulk_body_users_item_user_attributes.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UsersCreateEmailOnlyBulkBodyUsersItemUserAttributes") + + +@_attrs_define +class UsersCreateEmailOnlyBulkBodyUsersItemUserAttributes: + """Optional user attributes as key-value pairs""" + + additional_properties: dict[str, bool | float | None | str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + users_create_email_only_bulk_body_users_item_user_attributes = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property(data: object) -> bool | float | None | str: + if data is None: + return data + return cast(bool | float | None | str, data) + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + users_create_email_only_bulk_body_users_item_user_attributes.additional_properties = additional_properties + return users_create_email_only_bulk_body_users_item_user_attributes + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> bool | float | None | str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: bool | float | None | str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_create_email_only_bulk_response.py b/omni_python_sdk/models/users_create_email_only_bulk_response.py new file mode 100644 index 0000000..c4fd6c8 --- /dev/null +++ b/omni_python_sdk/models/users_create_email_only_bulk_response.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.users_create_email_only_bulk_response_results_item import UsersCreateEmailOnlyBulkResponseResultsItem + + +T = TypeVar("T", bound="UsersCreateEmailOnlyBulkResponse") + + +@_attrs_define +class UsersCreateEmailOnlyBulkResponse: + """ + Attributes: + results (list[UsersCreateEmailOnlyBulkResponseResultsItem]): Results for each created user + """ + + results: list[UsersCreateEmailOnlyBulkResponseResultsItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + results = [] + for results_item_data in self.results: + results_item = results_item_data.to_dict() + results.append(results_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "results": results, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.users_create_email_only_bulk_response_results_item import ( + UsersCreateEmailOnlyBulkResponseResultsItem, + ) + + d = dict(src_dict) + results = [] + _results = d.pop("results") + for results_item_data in _results: + results_item = UsersCreateEmailOnlyBulkResponseResultsItem.from_dict(results_item_data) + + results.append(results_item) + + users_create_email_only_bulk_response = cls( + results=results, + ) + + users_create_email_only_bulk_response.additional_properties = d + return users_create_email_only_bulk_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_create_email_only_bulk_response_results_item.py b/omni_python_sdk/models/users_create_email_only_bulk_response_results_item.py new file mode 100644 index 0000000..b24fc15 --- /dev/null +++ b/omni_python_sdk/models/users_create_email_only_bulk_response_results_item.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UsersCreateEmailOnlyBulkResponseResultsItem") + + +@_attrs_define +class UsersCreateEmailOnlyBulkResponseResultsItem: + """ + Attributes: + email (str): Email address of the created user Example: user@example.com. + user_id (UUID): ID of the created user + """ + + email: str + user_id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + email = self.email + + user_id = str(self.user_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "email": email, + "userId": user_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + email = d.pop("email") + + user_id = UUID(d.pop("userId")) + + users_create_email_only_bulk_response_results_item = cls( + email=email, + user_id=user_id, + ) + + users_create_email_only_bulk_response_results_item.additional_properties = d + return users_create_email_only_bulk_response_results_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_create_email_only_response.py b/omni_python_sdk/models/users_create_email_only_response.py new file mode 100644 index 0000000..9cc8d2a --- /dev/null +++ b/omni_python_sdk/models/users_create_email_only_response.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UsersCreateEmailOnlyResponse") + + +@_attrs_define +class UsersCreateEmailOnlyResponse: + """ + Attributes: + email (str): Email address of the created user Example: user@example.com. + user_id (UUID): ID of the created user + """ + + email: str + user_id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + email = self.email + + user_id = str(self.user_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "email": email, + "userId": user_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + email = d.pop("email") + + user_id = UUID(d.pop("userId")) + + users_create_email_only_response = cls( + email=email, + user_id=user_id, + ) + + users_create_email_only_response.additional_properties = d + return users_create_email_only_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_get_model_roles_response.py b/omni_python_sdk/models/users_get_model_roles_response.py new file mode 100644 index 0000000..6e3a71b --- /dev/null +++ b/omni_python_sdk/models/users_get_model_roles_response.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.role_assignment_result import RoleAssignmentResult + + +T = TypeVar("T", bound="UsersGetModelRolesResponse") + + +@_attrs_define +class UsersGetModelRolesResponse: + """ + Attributes: + membership_id (UUID): The user membership ID + results (list[RoleAssignmentResult]): List of role assignments + """ + + membership_id: UUID + results: list[RoleAssignmentResult] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + membership_id = str(self.membership_id) + + results = [] + for results_item_data in self.results: + results_item = results_item_data.to_dict() + results.append(results_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "membershipId": membership_id, + "results": results, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.role_assignment_result import RoleAssignmentResult + + d = dict(src_dict) + membership_id = UUID(d.pop("membershipId")) + + results = [] + _results = d.pop("results") + for results_item_data in _results: + results_item = RoleAssignmentResult.from_dict(results_item_data) + + results.append(results_item) + + users_get_model_roles_response = cls( + membership_id=membership_id, + results=results, + ) + + users_get_model_roles_response.additional_properties = d + return users_get_model_roles_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_list_email_only_response.py b/omni_python_sdk/models/users_list_email_only_response.py new file mode 100644 index 0000000..422d6f0 --- /dev/null +++ b/omni_python_sdk/models/users_list_email_only_response.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.page_info import PageInfo + from ..models.users_list_email_only_response_records_item import UsersListEmailOnlyResponseRecordsItem + + +T = TypeVar("T", bound="UsersListEmailOnlyResponse") + + +@_attrs_define +class UsersListEmailOnlyResponse: + """ + Attributes: + page_info (PageInfo): + records (list[UsersListEmailOnlyResponseRecordsItem]): + """ + + page_info: PageInfo + records: list[UsersListEmailOnlyResponseRecordsItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.page_info import PageInfo + from ..models.users_list_email_only_response_records_item import UsersListEmailOnlyResponseRecordsItem + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = UsersListEmailOnlyResponseRecordsItem.from_dict(records_item_data) + + records.append(records_item) + + users_list_email_only_response = cls( + page_info=page_info, + records=records, + ) + + users_list_email_only_response.additional_properties = d + return users_list_email_only_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_list_email_only_response_records_item.py b/omni_python_sdk/models/users_list_email_only_response_records_item.py new file mode 100644 index 0000000..499d25d --- /dev/null +++ b/omni_python_sdk/models/users_list_email_only_response_records_item.py @@ -0,0 +1,88 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.users_list_email_only_response_records_item_user_attributes import ( + UsersListEmailOnlyResponseRecordsItemUserAttributes, + ) + + +T = TypeVar("T", bound="UsersListEmailOnlyResponseRecordsItem") + + +@_attrs_define +class UsersListEmailOnlyResponseRecordsItem: + """ + Attributes: + email (str): User email address Example: user@example.com. + user_attributes (UsersListEmailOnlyResponseRecordsItemUserAttributes): User attributes as key-value pairs + user_id (UUID): User ID + """ + + email: str + user_attributes: UsersListEmailOnlyResponseRecordsItemUserAttributes + user_id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + email = self.email + + user_attributes = self.user_attributes.to_dict() + + user_id = str(self.user_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "email": email, + "user_attributes": user_attributes, + "user_id": user_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.users_list_email_only_response_records_item_user_attributes import ( + UsersListEmailOnlyResponseRecordsItemUserAttributes, + ) + + d = dict(src_dict) + email = d.pop("email") + + user_attributes = UsersListEmailOnlyResponseRecordsItemUserAttributes.from_dict(d.pop("user_attributes")) + + user_id = UUID(d.pop("user_id")) + + users_list_email_only_response_records_item = cls( + email=email, + user_attributes=user_attributes, + user_id=user_id, + ) + + users_list_email_only_response_records_item.additional_properties = d + return users_list_email_only_response_records_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_list_email_only_response_records_item_user_attributes.py b/omni_python_sdk/models/users_list_email_only_response_records_item_user_attributes.py new file mode 100644 index 0000000..605040d --- /dev/null +++ b/omni_python_sdk/models/users_list_email_only_response_records_item_user_attributes.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="UsersListEmailOnlyResponseRecordsItemUserAttributes") + + +@_attrs_define +class UsersListEmailOnlyResponseRecordsItemUserAttributes: + """User attributes as key-value pairs""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + users_list_email_only_response_records_item_user_attributes = cls() + + users_list_email_only_response_records_item_user_attributes.additional_properties = d + return users_list_email_only_response_records_item_user_attributes + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/users_list_email_only_sort_direction.py b/omni_python_sdk/models/users_list_email_only_sort_direction.py new file mode 100644 index 0000000..b39bb46 --- /dev/null +++ b/omni_python_sdk/models/users_list_email_only_sort_direction.py @@ -0,0 +1,14 @@ +from typing import Literal + +UsersListEmailOnlySortDirection = Literal["asc", "desc"] + +USERS_LIST_EMAIL_ONLY_SORT_DIRECTION_VALUES: set[UsersListEmailOnlySortDirection] = { + "asc", + "desc", +} + + +def check_users_list_email_only_sort_direction(value: str) -> UsersListEmailOnlySortDirection: + if value in USERS_LIST_EMAIL_ONLY_SORT_DIRECTION_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {USERS_LIST_EMAIL_ONLY_SORT_DIRECTION_VALUES!r}") diff --git a/omni_python_sdk/models/whoami_model_role.py b/omni_python_sdk/models/whoami_model_role.py new file mode 100644 index 0000000..8086cf4 --- /dev/null +++ b/omni_python_sdk/models/whoami_model_role.py @@ -0,0 +1,104 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.whoami_model_role_permissions_item import ( + WhoamiModelRolePermissionsItem, + check_whoami_model_role_permissions_item, +) + +T = TypeVar("T", bound="WhoamiModelRole") + + +@_attrs_define +class WhoamiModelRole: + """ + Attributes: + base_role (str): The resolved base role (for custom roles, the base role they extend). Example: QUERIER. + connection_id (str): The connection this model belongs to + permissions (list[WhoamiModelRolePermissionsItem]): The caller's resolved/effective permissions on this model, + reflecting custom roles. This is a capability signal for the directly-roleable model kinds (schema / shared / + extension). It does not enumerate the permissions you derive on branch, workbook, and query models from your + role on the base model they descend from — absence here does not mean you lack access on those derived models. + MANAGE_MODEL, READ, and REFRESH_SCHEMA are also not reported: they derive from connection / sibling-model roles + rather than a per-model rule. Example: ['QUERY_TOPICS', 'QUERY_SQL', 'USE_WORKBOOKS']. + role_name (str): The resolved role name (informational; may be a custom role). Use `permissions` to decide + capability. Example: QUERIER. + """ + + base_role: str + connection_id: str + permissions: list[WhoamiModelRolePermissionsItem] + role_name: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + base_role = self.base_role + + connection_id = self.connection_id + + permissions = [] + for permissions_item_data in self.permissions: + permissions_item: str = permissions_item_data + permissions.append(permissions_item) + + role_name = self.role_name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "baseRole": base_role, + "connectionId": connection_id, + "permissions": permissions, + "roleName": role_name, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + base_role = d.pop("baseRole") + + connection_id = d.pop("connectionId") + + permissions = [] + _permissions = d.pop("permissions") + for permissions_item_data in _permissions: + permissions_item = check_whoami_model_role_permissions_item(permissions_item_data) + + permissions.append(permissions_item) + + role_name = d.pop("roleName") + + whoami_model_role = cls( + base_role=base_role, + connection_id=connection_id, + permissions=permissions, + role_name=role_name, + ) + + whoami_model_role.additional_properties = d + return whoami_model_role + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/whoami_model_role_permissions_item.py b/omni_python_sdk/models/whoami_model_role_permissions_item.py new file mode 100644 index 0000000..3dc0b6d --- /dev/null +++ b/omni_python_sdk/models/whoami_model_role_permissions_item.py @@ -0,0 +1,41 @@ +from typing import Literal + +WhoamiModelRolePermissionsItem = Literal[ + "DOWNLOAD_CONTENT_QUERY", + "QUERY_FULL_MODEL", + "QUERY_SQL", + "QUERY_TOPICS", + "RUN_CONTENT_QUERIES", + "SAVE_SPREADSHEETS", + "SCHEDULE", + "UPDATE", + "UPDATE_RESTRICTED", + "UPLOAD_CSV", + "USE_AI", + "USE_IDE", + "USE_WORKBOOKS", + "VIEW_SQL", +] + +WHOAMI_MODEL_ROLE_PERMISSIONS_ITEM_VALUES: set[WhoamiModelRolePermissionsItem] = { + "DOWNLOAD_CONTENT_QUERY", + "QUERY_FULL_MODEL", + "QUERY_SQL", + "QUERY_TOPICS", + "RUN_CONTENT_QUERIES", + "SAVE_SPREADSHEETS", + "SCHEDULE", + "UPDATE", + "UPDATE_RESTRICTED", + "UPLOAD_CSV", + "USE_AI", + "USE_IDE", + "USE_WORKBOOKS", + "VIEW_SQL", +} + + +def check_whoami_model_role_permissions_item(value: str) -> WhoamiModelRolePermissionsItem: + if value in WHOAMI_MODEL_ROLE_PERMISSIONS_ITEM_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {WHOAMI_MODEL_ROLE_PERMISSIONS_ITEM_VALUES!r}") diff --git a/omni_python_sdk/models/whoami_response.py b/omni_python_sdk/models/whoami_response.py new file mode 100644 index 0000000..0159881 --- /dev/null +++ b/omni_python_sdk/models/whoami_response.py @@ -0,0 +1,109 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.whoami_response_key_scope import WhoamiResponseKeyScope, check_whoami_response_key_scope +from ..models.whoami_response_org_role import WhoamiResponseOrgRole, check_whoami_response_org_role +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.whoami_response_roles_by_model import WhoamiResponseRolesByModel + from ..models.whoami_user import WhoamiUser + + +T = TypeVar("T", bound="WhoamiResponse") + + +@_attrs_define +class WhoamiResponse: + """ + Attributes: + key_scope (WhoamiResponseKeyScope): Scope of the API key in use. A separate axis from role: a user-scoped key + (PAT/OAuth) acts as a single user and cannot use SCIM, regardless of the user's org role. + org_role (WhoamiResponseOrgRole): The caller's organization role. Example: MEMBER. + roles_by_model (WhoamiResponseRolesByModel): Resolved role and effective permissions per model, keyed by model + id. Connection role resolves per shared model, so this is per-model rather than a single global role. + user (WhoamiUser): + roles_by_model_truncated (bool | Unset): Present and `true` when `rolesByModel` was truncated because the caller + can access more models than the unfiltered limit. Pass a `modelId` filter to retrieve specific models. + """ + + key_scope: WhoamiResponseKeyScope + org_role: WhoamiResponseOrgRole + roles_by_model: WhoamiResponseRolesByModel + user: WhoamiUser + roles_by_model_truncated: bool | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + key_scope: str = self.key_scope + + org_role: str = self.org_role + + roles_by_model = self.roles_by_model.to_dict() + + user = self.user.to_dict() + + roles_by_model_truncated = self.roles_by_model_truncated + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "keyScope": key_scope, + "orgRole": org_role, + "rolesByModel": roles_by_model, + "user": user, + } + ) + if roles_by_model_truncated is not UNSET: + field_dict["rolesByModelTruncated"] = roles_by_model_truncated + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.whoami_response_roles_by_model import WhoamiResponseRolesByModel + from ..models.whoami_user import WhoamiUser + + d = dict(src_dict) + key_scope = check_whoami_response_key_scope(d.pop("keyScope")) + + org_role = check_whoami_response_org_role(d.pop("orgRole")) + + roles_by_model = WhoamiResponseRolesByModel.from_dict(d.pop("rolesByModel")) + + user = WhoamiUser.from_dict(d.pop("user")) + + roles_by_model_truncated = d.pop("rolesByModelTruncated", UNSET) + + whoami_response = cls( + key_scope=key_scope, + org_role=org_role, + roles_by_model=roles_by_model, + user=user, + roles_by_model_truncated=roles_by_model_truncated, + ) + + whoami_response.additional_properties = d + return whoami_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/whoami_response_key_scope.py b/omni_python_sdk/models/whoami_response_key_scope.py new file mode 100644 index 0000000..112d96f --- /dev/null +++ b/omni_python_sdk/models/whoami_response_key_scope.py @@ -0,0 +1,14 @@ +from typing import Literal + +WhoamiResponseKeyScope = Literal["organization", "user"] + +WHOAMI_RESPONSE_KEY_SCOPE_VALUES: set[WhoamiResponseKeyScope] = { + "organization", + "user", +} + + +def check_whoami_response_key_scope(value: str) -> WhoamiResponseKeyScope: + if value in WHOAMI_RESPONSE_KEY_SCOPE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {WHOAMI_RESPONSE_KEY_SCOPE_VALUES!r}") diff --git a/omni_python_sdk/models/whoami_response_org_role.py b/omni_python_sdk/models/whoami_response_org_role.py new file mode 100644 index 0000000..2b9a74e --- /dev/null +++ b/omni_python_sdk/models/whoami_response_org_role.py @@ -0,0 +1,14 @@ +from typing import Literal + +WhoamiResponseOrgRole = Literal["MEMBER", "ORG_ADMIN"] + +WHOAMI_RESPONSE_ORG_ROLE_VALUES: set[WhoamiResponseOrgRole] = { + "MEMBER", + "ORG_ADMIN", +} + + +def check_whoami_response_org_role(value: str) -> WhoamiResponseOrgRole: + if value in WHOAMI_RESPONSE_ORG_ROLE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {WHOAMI_RESPONSE_ORG_ROLE_VALUES!r}") diff --git a/omni_python_sdk/models/whoami_response_roles_by_model.py b/omni_python_sdk/models/whoami_response_roles_by_model.py new file mode 100644 index 0000000..1d1fac6 --- /dev/null +++ b/omni_python_sdk/models/whoami_response_roles_by_model.py @@ -0,0 +1,63 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.whoami_model_role import WhoamiModelRole + + +T = TypeVar("T", bound="WhoamiResponseRolesByModel") + + +@_attrs_define +class WhoamiResponseRolesByModel: + """Resolved role and effective permissions per model, keyed by model id. Connection role resolves per shared model, so + this is per-model rather than a single global role. + + """ + + additional_properties: dict[str, WhoamiModelRole] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + field_dict[prop_name] = prop.to_dict() + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.whoami_model_role import WhoamiModelRole + + d = dict(src_dict) + whoami_response_roles_by_model = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + additional_property = WhoamiModelRole.from_dict(prop_dict) + + additional_properties[prop_name] = additional_property + + whoami_response_roles_by_model.additional_properties = additional_properties + return whoami_response_roles_by_model + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> WhoamiModelRole: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: WhoamiModelRole) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/whoami_user.py b/omni_python_sdk/models/whoami_user.py new file mode 100644 index 0000000..df029a9 --- /dev/null +++ b/omni_python_sdk/models/whoami_user.py @@ -0,0 +1,70 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="WhoamiUser") + + +@_attrs_define +class WhoamiUser: + """ + Attributes: + id (str): The caller's user id + membership_id (str): The caller's own membership id within this organization. This is the id accepted by the + admin `GET /api/v1/users/{id}/model-roles` endpoint (it is distinct from the user id). + """ + + id: str + membership_id: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + id = self.id + + membership_id = self.membership_id + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "id": id, + "membershipId": membership_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + id = d.pop("id") + + membership_id = d.pop("membershipId") + + whoami_user = cls( + id=id, + membership_id=membership_id, + ) + + whoami_user.additional_properties = d + return whoami_user + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/py.typed b/omni_python_sdk/py.typed new file mode 100644 index 0000000..1aad327 --- /dev/null +++ b/omni_python_sdk/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561 \ No newline at end of file diff --git a/omni_python_sdk/types.py b/omni_python_sdk/types.py new file mode 100644 index 0000000..b64af09 --- /dev/null +++ b/omni_python_sdk/types.py @@ -0,0 +1,54 @@ +"""Contains some shared types for properties""" + +from collections.abc import Mapping, MutableMapping +from http import HTTPStatus +from typing import IO, BinaryIO, Generic, Literal, TypeVar + +from attrs import define + + +class Unset: + def __bool__(self) -> Literal[False]: + return False + + +UNSET: Unset = Unset() + +# The types that `httpx.Client(files=)` can accept, copied from that library. +FileContent = IO[bytes] | bytes | str +FileTypes = ( + # (filename, file (or bytes), content_type) + tuple[str | None, FileContent, str | None] + # (filename, file (or bytes), content_type, headers) + | tuple[str | None, FileContent, str | None, Mapping[str, str]] +) +RequestFiles = list[tuple[str, FileTypes]] + + +@define +class File: + """Contains information for file uploads""" + + payload: BinaryIO + file_name: str | None = None + mime_type: str | None = None + + def to_tuple(self) -> FileTypes: + """Return a tuple representation that httpx will accept for multipart/form-data""" + return self.file_name, self.payload, self.mime_type + + +T = TypeVar("T") + + +@define +class Response(Generic[T]): + """A response from an endpoint""" + + status_code: HTTPStatus + content: bytes + headers: MutableMapping[str, str] + parsed: T | None + + +__all__ = ["UNSET", "File", "FileTypes", "RequestFiles", "Response", "Unset"] From 13463342a9f0977546f38533ecd4d091672ea8c4 Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Thu, 16 Jul 2026 12:34:52 -0700 Subject: [PATCH 03/11] Add helpers layer, modern packaging, tests, README, and CI - omni_python_sdk/helpers.py (hand-written, preserved by generate.sh): client_from_env plus run/wait_query_blocking that decode the query API's NDJSON + base64 Arrow IPC payload into a pyarrow.Table - pyproject.toml (hatchling, v1.0.0, Python >=3.10) replacing setup.py/requirements.txt; fixes the broken dotenv dependency name - pytest suite: client smoke tests, all-endpoints import check, and mocked-transport tests for the query decode path - README rewritten for the generated client with 0.x migration notes - CI workflow: tests on 3.10/3.12 plus a generated-code drift check Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 40 ++++++++++ .gitignore | 3 +- README.md | 132 +++++++++++++++++++++++---------- omni_python_sdk/helpers.py | 95 ++++++++++++++++++++++++ pyproject.toml | 39 ++++++++++ tests/__init__.py | 0 tests/test_generated_client.py | 44 +++++++++++ tests/test_helpers.py | 119 +++++++++++++++++++++++++++++ 8 files changed, 432 insertions(+), 40 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 omni_python_sdk/helpers.py create mode 100644 pyproject.toml create mode 100644 tests/__init__.py create mode 100644 tests/test_generated_client.py create mode 100644 tests/test_helpers.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..19f5dec --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,40 @@ +name: CI + +on: + pull_request: + push: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.12"] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install + run: pip install -e '.[dev]' + - name: Run tests + run: pytest + + generated-code-drift: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Install generator + run: pip install 'openapi-python-client>=0.29.0,<0.30.0' + - name: Regenerate from checked-in spec + run: scripts/generate.sh + - name: Fail on drift + run: | + git diff --exit-code -- omni_python_sdk spec || { + echo '::error::Generated code is out of sync with spec/openapi.json. Run scripts/generate.sh and commit the result.' + exit 1 + } diff --git a/.gitignore b/.gitignore index df4abbd..42cae1d 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ __pycache__/ .DS_Store build/ dist/ -omni_python_sdk.egg-info/ \ No newline at end of file +omni_python_sdk.egg-info/ +.venv-test/ diff --git a/README.md b/README.md index 4d4285a..679ad97 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,120 @@ # omni-python-sdk -Python SDK for interacting with the Omni API +Python SDK for the [Omni Analytics API](https://docs.omni.co/docs/API/), generated from the official OpenAPI spec. Covers the full public API surface (195 endpoints across queries, documents, models, connections, SCIM user/group management, schedules, AI, and more), with typed request/response models and both sync and async support. ## Installation ```bash -pip install -r requirements.txt +pip install omni-python-sdk ``` -## Usage +Requires Python 3.10+. + +## Authentication + +Create an API key in Omni under **Settings → API Keys**, then either export it: + +```bash +export OMNI_API_KEY="your-api-key" +export OMNI_BASE_URL="https://myorg.omniapp.co" +``` + +(or put the same two lines in a `.env` file) and build a client: + +```python +from omni_python_sdk.helpers import client_from_env + +client = client_from_env() +``` + +Or construct one explicitly: + +```python +from omni_python_sdk import AuthenticatedClient + +client = AuthenticatedClient(base_url="https://myorg.omniapp.co", token="your-api-key") +``` + +## Running queries + +The query endpoints return Apache Arrow data. The `helpers` module handles polling and decoding for you: + ```python -from omni_python_sdk import OmniAPI +from omni_python_sdk.helpers import client_from_env, run_query_blocking -# Set your API key and base URL -api_key = "your_api_key" -base_url = "https://your_domain.omniapp.co" -#these can optionally be set in an .env file with the following keys: -# OMNI_API_KEY=<> -# OMNI_BASE_URL=<> +client = client_from_env() -# Define your query query = { "query": { - "sorts": [ - { - "column_name": "order_items.created_at[date]", - "sort_descending": False - } - ], + "limit": 100, + "sorts": [{"column_name": "order_items.created_at[date]"}], "table": "order_items", - "fields": [ - "order_items.created_at[date]", - "order_items.sale_price_sum" - ], - "modelId": "your_model_id", - "join_paths_from_topic_name": "order_items" + "fields": ["order_items.created_at[date]", "order_items.sale_price_sum"], + "modelId": "your-model-id", } } -# Initialize the API with your credentials -api = OmniAPI(api_key, base_url) -# if you've optionally set your keys in a .env file no arguments are required: -# api = OmniAPI() -# if your environment variables are stored in an alternative location -# api = OmniAPI(env_file='<>') +table, fields = run_query_blocking(client, query) # table is a pyarrow.Table +df = table.to_pandas() +``` + +Tip: copy a ready-made query body from any workbook via **View → Query Structure**. -# Run the query and get a table -table = api.run_query_blocking(query) +## Calling any endpoint -# Convert the table to a Pandas DataFrame -df = table.to_pandas() +Every API operation is a module under `omni_python_sdk.api.`, with four variants: `sync`, `sync_detailed`, `asyncio`, and `asyncio_detailed`. + +```python +from omni_python_sdk.api.whoami import whoami +from omni_python_sdk.api.scim import scim_users_list +from omni_python_sdk.api.documents import documents_create + +me = whoami.sync(client=client) + +users = scim_users_list.sync(client=client, count="50") + +response = documents_create.sync_detailed(client=client, body=...) +print(response.status_code, response.parsed) +``` + +Request/response models live in `omni_python_sdk.models` and convert to/from plain dicts with `.to_dict()` / `.from_dict()`. + +Async is the same modules: -# Display the first few rows of the DataFrame -print(df.head()) +```python +result = await whoami.asyncio(client=client) ``` -To run the example, you need to replace `your_api_key`, `your_domain`, and `your_model_id` with your own values. +See [`examples/`](examples/) for end-to-end scripts (queries, user management, document migration, embed sessions, semantic-view generation). + +## Migrating from 0.x + +Version 1.0 is a full rewrite: the hand-written `OmniAPI` class is gone, replaced by the generated client above. The most common patterns map as follows: + +| 0.x | 1.x | +|---|---| +| `OmniAPI()` | `client_from_env()` from `omni_python_sdk.helpers` | +| `api.run_query_blocking(body)` | `run_query_blocking(client, body)` from `omni_python_sdk.helpers` | +| `api.create_user(body)` etc. | `omni_python_sdk.api.scim.scim_users_create.sync(client=client, body=...)` etc. | +| `api.document_export(id)` | `omni_python_sdk.api.unstable.unstable_documents_export.sync(client=client, identifier=id)` | + +## Regenerating the SDK + +The client is generated from the vendored spec in `spec/openapi.json` using [openapi-python-client](https://github.com/openapi-generators/openapi-python-client): + +```bash +pip install openapi-python-client + +scripts/generate.sh # regenerate from the checked-in spec +scripts/generate.sh --url https://myorg.omniapp.co # sync the spec from a live instance first +scripts/generate.sh --source ../omni/packages/bi-app/app/types/api/openapi/openapi.json +``` -To get a query object, you can use the Inspector on a Omni Workbook. The query object is a JSON object that represents the query you want to run. You can find the Inspector in the View menu on a Workbook. Look for the "Query Structure" section. +The pipeline preprocesses the spec (`scripts/preprocess_spec.py`), regenerates `omni_python_sdk/` (preserving the hand-written `helpers.py`), and CI fails if the checked-in generated code drifts from the checked-in spec. -For a simple command line interface, you can run the following command: +## Development ```bash -python3 examples/query.py OMNI_API_KEY https://OMNI_URL '{"query": {"sorts": [{"column_name": "omni_dbt__order_items.created_at[date]", "sort_descending": false}], "table": "omni_dbt__order_items", "fields": ["omni_dbt__order_items.created_at[date]", "omni_dbt__order_items.total_sale_price"], "modelId": "OMNI_MODEL_ID", "join_paths_from_topic_name": "order_items"}} +pip install -e '.[dev]' +pytest ``` diff --git a/omni_python_sdk/helpers.py b/omni_python_sdk/helpers.py new file mode 100644 index 0000000..1a20556 --- /dev/null +++ b/omni_python_sdk/helpers.py @@ -0,0 +1,95 @@ +"""Hand-written conveniences on top of the generated client. + +This module is NOT generated. scripts/generate.sh preserves it across +regenerations; everything else in this package is overwritten. +""" + +import base64 +import io +import json +import os +from typing import Any + +import pyarrow as pa +import pyarrow.ipc as ipc +from dotenv import load_dotenv + +from .client import AuthenticatedClient + +__all__ = ["client_from_env", "run_query_blocking", "wait_query_blocking"] + + +def client_from_env(env_file: str = ".env", **kwargs: Any) -> AuthenticatedClient: + """Build an AuthenticatedClient from OMNI_API_KEY / OMNI_BASE_URL. + + Values are read from the environment, falling back to `env_file` if + present. OMNI_BASE_URL should be the bare instance origin, e.g. + https://myorg.omniapp.co — generated endpoint paths already include + /api/... prefixes. Extra kwargs are passed to AuthenticatedClient. + """ + load_dotenv(dotenv_path=env_file) + api_key = os.getenv("OMNI_API_KEY") + base_url = os.getenv("OMNI_BASE_URL") + if not api_key or not base_url: + raise ValueError("OMNI_API_KEY and OMNI_BASE_URL must be set (in the environment or in the env file)") + return AuthenticatedClient(base_url=_trim_base_url(base_url), token=api_key, **kwargs) + + +def _trim_base_url(base_url: str) -> str: + """Strip trailing slashes and /api[/v1|/unstable] suffixes so paths don't double up.""" + base_url = base_url.rstrip("/") + for suffix in ("/api/v1", "/api/unstable", "/api"): + if base_url.endswith(suffix): + base_url = base_url[: -len(suffix)] + return base_url + + +def run_query_blocking( + client: AuthenticatedClient, body: dict[str, Any], user_id: str | None = None +) -> tuple[pa.Table, list[dict[str, Any]]]: + """Run a query and block until it completes. + + POSTs /api/v1/query/run and polls /api/v1/query/wait until the job + finishes, then decodes the NDJSON + base64 Arrow IPC payload. + + Returns (pyarrow.Table, field metadata list). + """ + http = client.get_httpx_client() + params = {"userId": user_id} if user_id else None + response = http.post("/api/v1/query/run", json=body, params=params) + response.raise_for_status() + + lines = _ndjson(response.text) + footer = lines[-1] + done = footer["timed_out"] == "false" + while not done: + lines, done = wait_query_blocking(client, footer["remaining_job_ids"]) + footer = lines[-1] + + data_payload = next((line for line in lines if "result" in line), None) + if data_payload is None: + raise ValueError("No result found in the query response.") + + raw_arrow_data = base64.b64decode(data_payload["result"]) + with ipc.open_stream(io.BytesIO(raw_arrow_data)) as reader: + table = reader.read_all() + return table, data_payload["summary"]["fields"] + + +def wait_query_blocking( + client: AuthenticatedClient, remaining_job_ids: list[str] +) -> tuple[list[dict[str, Any]], bool]: + """Wait on running query jobs via /api/v1/query/wait. + + Returns (parsed NDJSON lines, done flag). + """ + http = client.get_httpx_client() + response = http.get("/api/v1/query/wait", params={"job_ids": json.dumps(remaining_job_ids)}) + response.raise_for_status() + lines = _ndjson(response.text) + done = lines[-1]["timed_out"] == "false" + return lines, done + + +def _ndjson(text: str) -> list[dict[str, Any]]: + return [json.loads(line) for line in text.splitlines() if line.strip()] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..0ac8da2 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,39 @@ +[project] +name = "omni-python-sdk" +version = "1.0.0" +description = "Python SDK for the Omni Analytics API, generated from the official OpenAPI spec" +authors = [{ name = "Omni Analytics", email = "support@omni.co" }] +license = { text = "MIT" } +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "httpx>=0.23.1,<0.29.0", + "attrs>=22.2.0", + "pyarrow>=14.0.0", + "python-dotenv>=1.0.0", +] + +[project.urls] +Homepage = "https://github.com/exploreomni/omni-python-sdk" +Documentation = "https://docs.omni.co/docs/API/" + +[project.optional-dependencies] +dev = [ + "pytest>=8.0.0", + "openapi-python-client>=0.29.0,<0.30.0", + "ruff", + "pandas", +] + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.build.targets.wheel] +packages = ["omni_python_sdk"] + +[tool.ruff] +line-length = 120 + +[tool.pytest.ini_options] +testpaths = ["tests"] diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_generated_client.py b/tests/test_generated_client.py new file mode 100644 index 0000000..6f994ff --- /dev/null +++ b/tests/test_generated_client.py @@ -0,0 +1,44 @@ +"""Smoke tests for the generated client package.""" + +import importlib +import pkgutil + +import pytest + +from omni_python_sdk import AuthenticatedClient, Client +import omni_python_sdk.api as api_pkg + + +def test_construct_clients(): + client = Client(base_url="https://example.omniapp.co") + authed = AuthenticatedClient(base_url="https://example.omniapp.co", token="test-token") + assert client.get_httpx_client().base_url == "https://example.omniapp.co" + assert authed.get_httpx_client().headers["authorization"] == "Bearer test-token" + + +@pytest.mark.parametrize( + "module", + [ + "omni_python_sdk.api.query.query_run", + "omni_python_sdk.api.query.query_wait", + "omni_python_sdk.api.scim.scim_users_list", + "omni_python_sdk.api.scim.scim_groups_list", + "omni_python_sdk.api.documents.documents_create", + "omni_python_sdk.api.whoami.whoami", + ], +) +def test_endpoint_modules_importable(module): + mod = importlib.import_module(module) + assert hasattr(mod, "sync_detailed") + assert hasattr(mod, "asyncio_detailed") + + +def test_all_endpoint_modules_import(): + """Every generated endpoint module must import cleanly.""" + count = 0 + for tag in pkgutil.iter_modules(api_pkg.__path__): + tag_pkg = importlib.import_module(f"omni_python_sdk.api.{tag.name}") + for op in pkgutil.iter_modules(tag_pkg.__path__): + importlib.import_module(f"omni_python_sdk.api.{tag.name}.{op.name}") + count += 1 + assert count >= 190, f"expected ~195 endpoint modules, found {count}" diff --git a/tests/test_helpers.py b/tests/test_helpers.py new file mode 100644 index 0000000..fdffbd9 --- /dev/null +++ b/tests/test_helpers.py @@ -0,0 +1,119 @@ +"""Tests for the hand-written helper layer (query -> pyarrow decoding).""" + +import base64 +import io +import json + +import httpx +import pyarrow as pa +import pyarrow.ipc as ipc +import pytest + +from omni_python_sdk import AuthenticatedClient +from omni_python_sdk.helpers import client_from_env, run_query_blocking, wait_query_blocking + + +def _arrow_payload(table: pa.Table) -> str: + buf = io.BytesIO() + with ipc.new_stream(buf, table.schema) as writer: + writer.write_table(table) + return base64.b64encode(buf.getvalue()).decode() + + +TABLE = pa.table({"city": ["Boston", "Denver"], "count": [3, 5]}) +FIELDS = [{"fieldName": "city"}, {"fieldName": "count"}] + + +def _ndjson_response(lines: list[dict]) -> httpx.Response: + return httpx.Response(200, text="\n".join(json.dumps(line) for line in lines)) + + +def _client_with_transport(handler) -> AuthenticatedClient: + return AuthenticatedClient( + base_url="https://example.omniapp.co", + token="test-token", + httpx_args={"transport": httpx.MockTransport(handler)}, + ) + + +def test_run_query_blocking_decodes_arrow(): + def handler(request: httpx.Request) -> httpx.Response: + assert request.url.path == "/api/v1/query/run" + assert request.headers["authorization"] == "Bearer test-token" + return _ndjson_response( + [ + {"result": _arrow_payload(TABLE), "summary": {"fields": FIELDS}}, + {"timed_out": "false"}, + ] + ) + + table, fields = run_query_blocking(_client_with_transport(handler), {"query": {}}) + assert table.equals(TABLE) + assert fields == FIELDS + + +def test_run_query_blocking_polls_wait_until_done(): + calls = [] + + def handler(request: httpx.Request) -> httpx.Response: + calls.append(request.url.path) + if request.url.path == "/api/v1/query/run": + return _ndjson_response([{"timed_out": "true", "remaining_job_ids": ["job-1"]}]) + assert request.url.path == "/api/v1/query/wait" + assert json.loads(request.url.params["job_ids"]) == ["job-1"] + if len(calls) < 3: + return _ndjson_response([{"timed_out": "true", "remaining_job_ids": ["job-1"]}]) + return _ndjson_response( + [ + {"result": _arrow_payload(TABLE), "summary": {"fields": FIELDS}}, + {"timed_out": "false"}, + ] + ) + + table, fields = run_query_blocking(_client_with_transport(handler), {"query": {}}) + assert calls == ["/api/v1/query/run", "/api/v1/query/wait", "/api/v1/query/wait"] + assert table.equals(TABLE) + + +def test_run_query_blocking_no_result_raises(): + def handler(request: httpx.Request) -> httpx.Response: + return _ndjson_response([{"timed_out": "false"}]) + + with pytest.raises(ValueError, match="No result"): + run_query_blocking(_client_with_transport(handler), {"query": {}}) + + +def test_run_query_blocking_http_error_raises(): + def handler(request: httpx.Request) -> httpx.Response: + return httpx.Response(403, json={"error": "forbidden"}) + + with pytest.raises(httpx.HTTPStatusError): + run_query_blocking(_client_with_transport(handler), {"query": {}}) + + +def test_wait_query_blocking_done_flag(): + def handler(request: httpx.Request) -> httpx.Response: + return _ndjson_response([{"timed_out": "true", "remaining_job_ids": ["job-1"]}]) + + lines, done = wait_query_blocking(_client_with_transport(handler), ["job-1"]) + assert done is False + assert lines[-1]["remaining_job_ids"] == ["job-1"] + + +def test_client_from_env(tmp_path, monkeypatch): + monkeypatch.delenv("OMNI_API_KEY", raising=False) + monkeypatch.delenv("OMNI_BASE_URL", raising=False) + env_file = tmp_path / ".env" + env_file.write_text("OMNI_API_KEY=abc123\nOMNI_BASE_URL=https://example.omniapp.co/api/v1\n") + + client = client_from_env(env_file=str(env_file)) + # /api/v1 suffix is trimmed; token becomes a bearer header + assert str(client.get_httpx_client().base_url) == "https://example.omniapp.co" + assert client.get_httpx_client().headers["authorization"] == "Bearer abc123" + + +def test_client_from_env_missing_raises(tmp_path, monkeypatch): + monkeypatch.delenv("OMNI_API_KEY", raising=False) + monkeypatch.delenv("OMNI_BASE_URL", raising=False) + with pytest.raises(ValueError, match="OMNI_API_KEY"): + client_from_env(env_file=str(tmp_path / "missing.env")) From d23b5db8d9739ba31227445107d8ca132afe2674 Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Thu, 16 Jul 2026 12:36:25 -0700 Subject: [PATCH 04/11] Pin PYTHONHASHSEED for deterministic generation Mixed-case enum values (e.g. Literal["Remove", "remove"]) were emitted in set-iteration order, which varies with Python's hash randomization and would make the CI drift check flaky. Pin the seed in generate.sh and commit the canonical seed-0 output. Co-Authored-By: Claude Fable 5 --- .../scim_groups_patch_body_operations_item_type_2_op.py | 4 ++-- .../models/scim_user_patch_request_operations_item_op.py | 6 +++--- scripts/generate.sh | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_op.py b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_op.py index 44a0e7a..5edf355 100644 --- a/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_op.py +++ b/omni_python_sdk/models/scim_groups_patch_body_operations_item_type_2_op.py @@ -1,10 +1,10 @@ from typing import Literal -ScimGroupsPatchBodyOperationsItemType2Op = Literal["add", "Add"] +ScimGroupsPatchBodyOperationsItemType2Op = Literal["Add", "add"] SCIM_GROUPS_PATCH_BODY_OPERATIONS_ITEM_TYPE_2_OP_VALUES: set[ScimGroupsPatchBodyOperationsItemType2Op] = { - "add", "Add", + "add", } diff --git a/omni_python_sdk/models/scim_user_patch_request_operations_item_op.py b/omni_python_sdk/models/scim_user_patch_request_operations_item_op.py index e399337..9497dd3 100644 --- a/omni_python_sdk/models/scim_user_patch_request_operations_item_op.py +++ b/omni_python_sdk/models/scim_user_patch_request_operations_item_op.py @@ -1,14 +1,14 @@ from typing import Literal -ScimUserPatchRequestOperationsItemOp = Literal["Add", "add", "Remove", "remove", "Replace", "replace"] +ScimUserPatchRequestOperationsItemOp = Literal["Add", "add", "remove", "Remove", "replace", "Replace"] SCIM_USER_PATCH_REQUEST_OPERATIONS_ITEM_OP_VALUES: set[ScimUserPatchRequestOperationsItemOp] = { "Add", "add", - "Remove", "remove", - "Replace", + "Remove", "replace", + "Replace", } diff --git a/scripts/generate.sh b/scripts/generate.sh index c3aa0a9..868d33b 100755 --- a/scripts/generate.sh +++ b/scripts/generate.sh @@ -11,6 +11,10 @@ set -euo pipefail +# Enum value ordering in generated code depends on Python set iteration +# order; pin the hash seed so regeneration is deterministic. +export PYTHONHASHSEED=0 + REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" SPEC="$REPO_ROOT/spec/openapi.json" PROCESSED="$REPO_ROOT/spec/openapi.processed.json" From 9870fbf32e5cff51c58039f42b852482846ec52b Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Thu, 16 Jul 2026 12:44:10 -0700 Subject: [PATCH 05/11] Port examples to the generated client - query.py / example_usage.py: AuthenticatedClient + run_query_blocking - content_migration.py: unstable_documents_export/import modules - model.py: fixes the broken update_field call using models_update_field - generate_embed_url.py: raw httpx call (endpoint not in the public spec) - user_management: new scim_helpers.py reimplementing upsert/group membership on the generated SCIM modules - semantic-view examples: models_get_topic for topic fetch Co-Authored-By: Claude Fable 5 --- examples/content_migration.py | 16 ++- examples/databricks_metric_view.py | 14 ++- examples/example_usage.py | 36 +++--- examples/generate_embed_url.py | 27 +++-- examples/model.py | 27 +++-- examples/query.py | 11 +- examples/snowflake_semantic_view.py | 14 ++- examples/user_management/scim_helpers.py | 108 ++++++++++++++++++ .../user_management/user_groups_management.py | 19 +-- examples/user_management/user_management.py | 14 ++- 10 files changed, 212 insertions(+), 74 deletions(-) create mode 100644 examples/user_management/scim_helpers.py diff --git a/examples/content_migration.py b/examples/content_migration.py index 3728225..c5c7aba 100644 --- a/examples/content_migration.py +++ b/examples/content_migration.py @@ -1,14 +1,18 @@ -from omni_python_sdk import OmniAPI +from omni_python_sdk import AuthenticatedClient +from omni_python_sdk.api.unstable import unstable_documents_export, unstable_documents_import +from omni_python_sdk.models import DocumentImportBody api_key = '<>' base_url = '<>' -# Initialize the API with your credentials -api = OmniAPI(api_key, base_url) +# Initialize the client with your credentials +client = AuthenticatedClient(base_url=base_url, token=api_key) # retrieve the dashboard -dashboard_export = api.document_export('<>') +dashboard_export = unstable_documents_export.sync( + '<>', client=client +).to_dict() # change the dashboard model id -dashboard_export.update({'baseModelId':'<< model id of new location >>'}) +dashboard_export.update({'baseModelId': '<< model id of new location >>'}) # import the modified document -api.document_import(dashboard_export) \ No newline at end of file +unstable_documents_import.sync(client=client, body=DocumentImportBody.from_dict(dashboard_export)) diff --git a/examples/databricks_metric_view.py b/examples/databricks_metric_view.py index 6f1ca4a..352a180 100644 --- a/examples/databricks_metric_view.py +++ b/examples/databricks_metric_view.py @@ -2,12 +2,14 @@ from typing import Optional import yaml import sys +from uuid import UUID from examples.topic import Topic -from omni_python_sdk import OmniAPI +from omni_python_sdk.api.models import models_get_topic +from omni_python_sdk.helpers import client_from_env -# Example of using the OmniAPI to get a topic definition and convert to a Snowflake semantic view -# This example assumes you have a valid API key and base URL for the OmniAPI defined in your .env file +# Example of using the Omni API to get a topic definition and convert to a Databricks metric view +# This example assumes you have OMNI_API_KEY and OMNI_BASE_URL defined in your .env file # SQL Reference # CREATE VIEW @@ -264,10 +266,10 @@ def replace_field(match): return metric_view def main(model_id: str, topic_name: str, default_catalog: Optional[str], default_schema: Optional[str]): - client = OmniAPI() + client = client_from_env() - response = client.get_topic(model_id=model_id, topic_name=topic_name) - topic = Topic.model_validate(response) + response = models_get_topic.sync(UUID(model_id), topic_name, client=client) + topic = Topic.model_validate(response.topic.to_dict()) metric_view = metric_view_from_topic(topic, default_catalog, default_schema) print(metric_view.generate_sql()) diff --git a/examples/example_usage.py b/examples/example_usage.py index 6be39bf..8a34b33 100644 --- a/examples/example_usage.py +++ b/examples/example_usage.py @@ -1,4 +1,4 @@ -from omni_python_sdk import OmniAPI +from omni_python_sdk.helpers import client_from_env, run_query_blocking import pandas as pd import matplotlib.pyplot as plt from statsmodels.tsa.statespace.sarimax import SARIMAX @@ -41,24 +41,26 @@ def plot_and_forecast(df: pd.DataFrame): plt.show() if __name__ == "__main__": - api_key = "your_api_key" query = { - "sorts": [ - { - "column_name": "order_items.created_at[date]", - "sort_descending": False - } - ], - "table": "order_items", - "fields": [ - "order_items.created_at[date]", - "order_items.sale_price_sum" - ], - "modelId": "55d8bd00-67ab-4519-853c-282cafd7e085", - "join_paths_from_topic_name": "order_items" + "query": { + "sorts": [ + { + "column_name": "order_items.created_at[date]", + "sort_descending": False + } + ], + "table": "order_items", + "fields": [ + "order_items.created_at[date]", + "order_items.sale_price_sum" + ], + "modelId": "55d8bd00-67ab-4519-853c-282cafd7e085", + "join_paths_from_topic_name": "order_items" + } } - api = OmniAPI(api_key) - table = api.run_query_blocking(query) + # Reads OMNI_API_KEY and OMNI_BASE_URL from the environment or a .env file + client = client_from_env() + table, fields = run_query_blocking(client, query) df = table.to_pandas() plot_and_forecast(df) diff --git a/examples/generate_embed_url.py b/examples/generate_embed_url.py index 5de20dd..ee73ce4 100644 --- a/examples/generate_embed_url.py +++ b/examples/generate_embed_url.py @@ -1,15 +1,20 @@ -from omni_python_sdk import OmniAPI +from omni_python_sdk import AuthenticatedClient -api = OmniAPI('<>','https://<>') +client = AuthenticatedClient(base_url='https://<>', token='<>') -response = api.generate_embed_url( - { - 'contentPath': '/dashboards/example_metrics', - 'externalId': 'user@example.com', - 'name': 'Example (embed test user)', - 'secret': '<>', - 'email':'user@example.com', - 'groups':'["my-example-group-name","second-group"]' - } +# The /embed/sso/generate-url endpoint is not part of the public OpenAPI spec, +# so call it through the client's underlying httpx client (auth and base_url +# are already configured). +response = client.get_httpx_client().post( + '/embed/sso/generate-url', + json={ + 'contentPath': '/dashboards/example_metrics', + 'externalId': 'user@example.com', + 'name': 'Example (embed test user)', + 'secret': '<>', + 'email': 'user@example.com', + 'groups': '["my-example-group-name","second-group"]' + } ) +response.raise_for_status() print(response.json()["url"]) diff --git a/examples/model.py b/examples/model.py index baad5af..9168a5c 100644 --- a/examples/model.py +++ b/examples/model.py @@ -1,14 +1,23 @@ import sys import json -from omni_python_sdk import OmniAPI +from uuid import UUID +from omni_python_sdk import AuthenticatedClient +from omni_python_sdk.api.models import models_update_field +from omni_python_sdk.models import ModelsUpdateFieldBody # Example script to update a field in a model with a JSON object -def main(api_key: str, base_url: str, model_id: str, view_name: str, field_name: str, json: dict): - # Initialize the OmniAPI client - client = OmniAPI(api_key, base_url) - - result = client.update_field(model_id, view_name, field_name, json) - +def main(api_key: str, base_url: str, model_id: str, view_name: str, field_name: str, field_json: dict): + # Initialize the client + client = AuthenticatedClient(base_url=base_url, token=api_key) + + result = models_update_field.sync( + UUID(model_id), + view_name, + field_name, + client=client, + body=ModelsUpdateFieldBody.from_dict(field_json), + ) + print(result) if __name__ == "__main__": @@ -21,6 +30,6 @@ def main(api_key: str, base_url: str, model_id: str, view_name: str, field_name: model_id = sys.argv[3] view_name = sys.argv[4] field_name = sys.argv[5] - json = json.loads(sys.argv[6]) + field_json = json.loads(sys.argv[6]) - main(api_key, base_url, model_id, view_name, field_name, json) \ No newline at end of file + main(api_key, base_url, model_id, view_name, field_name, field_json) diff --git a/examples/query.py b/examples/query.py index 4ca1dbc..2dcf38b 100644 --- a/examples/query.py +++ b/examples/query.py @@ -1,16 +1,17 @@ import sys import json import pandas as pd -from omni_python_sdk import OmniAPI +from omni_python_sdk import AuthenticatedClient +from omni_python_sdk.helpers import run_query_blocking from typing import Any, Dict def main(api_key: str, base_url: str, json_query: Dict[str, Any]): - # Initialize the OmniAPI client - client = OmniAPI(api_key, base_url) + # Initialize the client + client = AuthenticatedClient(base_url=base_url, token=api_key) # Execute the query - result, fields = client.run_query_blocking(json_query) + result, fields = run_query_blocking(client, json_query) # Create a mapping from raw column names to their labels column_mapping = {field_name: metadata.get('label', field_name) for field_name, metadata in fields.items()} @@ -37,4 +38,4 @@ def main(api_key: str, base_url: str, json_query: Dict[str, Any]): base_url = sys.argv[2] json_query = json.loads(sys.argv[3]) - main(api_key, base_url, json_query) \ No newline at end of file + main(api_key, base_url, json_query) diff --git a/examples/snowflake_semantic_view.py b/examples/snowflake_semantic_view.py index ef47834..0ffc2e3 100755 --- a/examples/snowflake_semantic_view.py +++ b/examples/snowflake_semantic_view.py @@ -1,9 +1,11 @@ import sys +from uuid import UUID from examples.topic import Topic -from omni_python_sdk import OmniAPI +from omni_python_sdk.api.models import models_get_topic +from omni_python_sdk.helpers import client_from_env -# Example of using the OmniAPI to get a topic definition and convert to a Snowflake semantic view -# This example assumes you have a valid API key and base URL for the OmniAPI defined in your .env file +# Example of using the Omni API to get a topic definition and convert to a Snowflake semantic view +# This example assumes you have OMNI_API_KEY and OMNI_BASE_URL defined in your .env file # https://docs.snowflake.com/en/user-guide/views-semantic/sql#label-semantic-views-create @@ -201,10 +203,10 @@ def sematic_view_from_topic(topic): return semantic_view def main(model_id: str, topic_name: str): - client = OmniAPI() + client = client_from_env() - response = client.get_topic(model_id=model_id, topic_name=topic_name) - topic = Topic.model_validate(response) + response = models_get_topic.sync(UUID(model_id), topic_name, client=client) + topic = Topic.model_validate(response.topic.to_dict()) semantic_view = sematic_view_from_topic(topic) print(semantic_view.generate_sql()) diff --git a/examples/user_management/scim_helpers.py b/examples/user_management/scim_helpers.py new file mode 100644 index 0000000..4729aa5 --- /dev/null +++ b/examples/user_management/scim_helpers.py @@ -0,0 +1,108 @@ +"""Small SCIM conveniences shared by the user management examples. + +These reimplement the upsert/group-membership helpers from the 0.x SDK on +top of the generated client. +""" + +from uuid import UUID + +from omni_python_sdk import AuthenticatedClient +from omni_python_sdk.api.scim import ( + scim_groups_get, + scim_groups_list, + scim_groups_replace, + scim_users_create, + scim_users_delete, + scim_users_list, + scim_users_replace, +) +from omni_python_sdk.models import ScimGroupsReplaceBody, ScimUserCreateRequest, ScimUserPutRequest + + +def listify(d: dict) -> dict: + """Convert string representations of lists ("[a,b]") to actual lists.""" + out = {} + for k, v in d.items(): + if '[' in v and ']' in v: + out.update({k: [item for item in v.replace('[', '').replace(']', '').split(',')]}) + else: + out.update({k: v}) + return out + + +def return_user_by_email(client: AuthenticatedClient, email: str) -> dict | None: + """Find a user by email; returns the SCIM user dict, or None if not exactly one match.""" + response = scim_users_list.sync(client=client, filter_=f'userName eq "{email}"') + users = response.to_dict()['Resources'] + if len(users) == 1: + return users[0] + print(f"Found {len(users)} users for {email}") + return None + + +def upsert_user(client: AuthenticatedClient, email: str, display_name: str, attributes: dict) -> None: + """Create the user, or replace it if it already exists.""" + body = { + "urn:omni:params:1.0:UserAttribute": listify(attributes), + "userName": email, + "displayName": display_name, + } + response = scim_users_list.sync(client=client, filter_=f'userName eq "{email}"') + users = response.to_dict()['Resources'] + if len(users) == 1: + user = users[0] + scim_users_replace.sync(UUID(user['id']), client=client, body=ScimUserPutRequest.from_dict(body)) + print(f"updated user id {user['id']}") + elif len(users) == 0: + created = scim_users_create.sync(client=client, body=ScimUserCreateRequest.from_dict(body)) + print(f"Created {email}, userid: {created.to_dict()['id']}") + else: + print(f'{len(users)} found for {email}, no action taken') + + +def delete_user(client: AuthenticatedClient, email: str) -> None: + """Delete a user by email address.""" + user = return_user_by_email(client, email) + if user is None: + print(f'user {email} not found') + return + response = scim_users_delete.sync_detailed(UUID(user['id']), client=client) + if response.status_code == 204: + print(f"deleted userid: {user['id']} email: {email}") + else: + print(f"Error ({response.status_code}) deleting user id {user['id']}") + + +def get_group_id(client: AuthenticatedClient, group_name: str) -> str | None: + """Get the ID of a group by display name (paginates through all groups).""" + count = 100 + start_index = 1 + while True: + response = scim_groups_list.sync(client=client, count=str(count), start_index=str(start_index)).to_dict() + group = next((g for g in response['Resources'] if g['displayName'] == group_name), None) + if group: + return group['id'] + if response['totalResults'] <= start_index: + return None + start_index += count + + +def _update_group_members(client: AuthenticatedClient, group_name: str, mutate) -> None: + group_id = get_group_id(client, group_name) + if not group_id: + raise ValueError(f"Group '{group_name}' not found.") + group = scim_groups_get.sync(group_id, client=client).to_dict() + group['members'] = mutate(group.get('members', [])) + scim_groups_replace.sync(group_id, client=client, body=ScimGroupsReplaceBody.from_dict(group)) + + +def add_user_to_group(client: AuthenticatedClient, group_name: str, user_id: str) -> None: + """Add a user to a group by group display name.""" + _update_group_members(client, group_name, lambda members: members + [{"display": '', "value": user_id}]) + + +def remove_user_from_group(client: AuthenticatedClient, group_name: str, user_id: str) -> None: + """Remove a user from a group by group display name.""" + _update_group_members( + client, group_name, lambda members: [m for m in members if m['value'] != user_id] + ) diff --git a/examples/user_management/user_groups_management.py b/examples/user_management/user_groups_management.py index bc9301c..253be48 100644 --- a/examples/user_management/user_groups_management.py +++ b/examples/user_management/user_groups_management.py @@ -1,12 +1,13 @@ -from omni_python_sdk import OmniAPI +from omni_python_sdk import AuthenticatedClient +from scim_helpers import return_user_by_email, add_user_to_group, remove_user_from_group import csv, time api_key = '<>' base_url = 'https://<>' -# Initialize the API with your credentials -api = OmniAPI(api_key, base_url) +# Initialize the client with your credentials +client = AuthenticatedClient(base_url=base_url, token=api_key) with open('user_groups.csv', newline='') as csvfile: user_groups = csv.DictReader(csvfile) @@ -15,14 +16,16 @@ email = row.pop('email') op = row.pop('op') if op == '+': - user = api.return_user_by_email(email) - api.add_user_to_group( + user = return_user_by_email(client, email) + add_user_to_group( + client, row['group_name'], user['id'] ) elif op == '-': - user = api.return_user_by_email(email) - api.remove_user_from_group( + user = return_user_by_email(client, email) + remove_user_from_group( + client, row['group_name'], user['id'] - ) \ No newline at end of file + ) diff --git a/examples/user_management/user_management.py b/examples/user_management/user_management.py index a78143c..f2f6ca1 100644 --- a/examples/user_management/user_management.py +++ b/examples/user_management/user_management.py @@ -1,12 +1,13 @@ -from omni_python_sdk import OmniAPI +from omni_python_sdk import AuthenticatedClient +from scim_helpers import upsert_user, delete_user import csv, time api_key = '<>' base_url = 'https://<>' -# Initialize the API with your credentials -api = OmniAPI(api_key, base_url) +# Initialize the client with your credentials +client = AuthenticatedClient(base_url=base_url, token=api_key) with open('users.csv', newline='') as csvfile: spamreader = csv.DictReader(csvfile) @@ -16,10 +17,11 @@ displayName = row.pop('display_name') op = row.pop('op') if op == 'upsert': - r1 = api.upsert_user( + upsert_user( + client, email=email, - displayName=displayName, + display_name=displayName, attributes=row ) elif op == 'delete': - api.delete_user(email) \ No newline at end of file + delete_user(client, email) From d058ef611540b48c0ff7a5f02fa92c40991cc16a Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Thu, 16 Jul 2026 12:53:15 -0700 Subject: [PATCH 06/11] Add generated-code conventions: gitattributes, provenance, policy docs - Mark generated files linguist-generated so GitHub collapses them in PR diffs (helpers.py stays reviewable) - Stop tracking spec/openapi.processed.json (derived; rebuilt by generate.sh) - Record spec provenance (source, omni commit SHA, sha256, timestamp) in spec/provenance.json on each spec sync - Document the generated-code review contract and SDK versioning policy in the README Co-Authored-By: Claude Fable 5 --- .gitattributes | 6 + .gitignore | 1 + README.md | 16 +- scripts/generate.sh | 22 + spec/openapi.processed.json | 25769 ---------------------------------- spec/provenance.json | 5 + 6 files changed, 49 insertions(+), 25770 deletions(-) create mode 100644 .gitattributes delete mode 100644 spec/openapi.processed.json create mode 100644 spec/provenance.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f7bdae2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +# Collapse generated code in GitHub diffs and exclude it from language stats. +# Reviewers should review spec/openapi.json changes and hand-written files; +# CI's drift check guarantees the generated code matches the spec. +omni_python_sdk/** linguist-generated=true +omni_python_sdk/helpers.py linguist-generated=false +spec/openapi.json linguist-generated=true diff --git a/.gitignore b/.gitignore index 42cae1d..d4687f3 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ build/ dist/ omni_python_sdk.egg-info/ .venv-test/ +spec/openapi.processed.json diff --git a/README.md b/README.md index 679ad97..2facac7 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,21 @@ scripts/generate.sh --url https://myorg.omniapp.co # sync the spec from a live scripts/generate.sh --source ../omni/packages/bi-app/app/types/api/openapi/openapi.json ``` -The pipeline preprocesses the spec (`scripts/preprocess_spec.py`), regenerates `omni_python_sdk/` (preserving the hand-written `helpers.py`), and CI fails if the checked-in generated code drifts from the checked-in spec. +The pipeline preprocesses the spec (`scripts/preprocess_spec.py`), regenerates `omni_python_sdk/` (preserving the hand-written `helpers.py`), and CI fails if the checked-in generated code drifts from the checked-in spec. When the spec is synced (`--source`/`--url`), `spec/provenance.json` records where it came from — including the omni repo commit SHA — so every SDK version is traceable to an exact API state. + +## Generated code policy + +Everything in `omni_python_sdk/` **except `helpers.py`** is generated — don't edit it by hand; changes belong in the spec (upstream in the omni repo) or in the generation pipeline. Generated files are marked `linguist-generated` in `.gitattributes`, so GitHub collapses them in PR diffs. + +**Reviewing a spec-sync PR:** review the `spec/openapi.json` diff and any hand-written changes; skip the generated diff. That's safe because CI's drift check proves the generated code is a pure function of the checked-in spec. + +**Versioning:** the SDK follows its own semver, independent of the API's `info.version`: + +- **Major** — breaking changes to the generated surface (removed/renamed endpoints, fields, or types) or to `helpers.py` +- **Minor** — new endpoints, models, or optional fields (most spec syncs) +- **Patch** — regeneration fixes, docs, dependency bumps + +Generator upgrades (the `openapi-python-client` pin in `pyproject.toml`) can rewrite every generated file with no API change — land those as their own clearly-labeled PR, never mixed with a spec sync. ## Development diff --git a/scripts/generate.sh b/scripts/generate.sh index 868d33b..ad79206 100755 --- a/scripts/generate.sh +++ b/scripts/generate.sh @@ -21,11 +21,33 @@ PROCESSED="$REPO_ROOT/spec/openapi.processed.json" CONFIG="$REPO_ROOT/generator/config.yaml" PKG="$REPO_ROOT/omni_python_sdk" +# record_provenance +# Only written when the spec is synced, so plain regeneration (and the CI +# drift check) stays deterministic. +record_provenance() { + python - "$SPEC" "$1" <<'PYEOF' +import datetime, hashlib, json, sys +spec, source = sys.argv[1], sys.argv[2] +digest = hashlib.sha256(open(spec, "rb").read()).hexdigest() +provenance = { + "source": source, + "spec_sha256": digest, + "synced_at": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), +} +path = spec.rsplit("/", 1)[0] + "/provenance.json" +json.dump(provenance, open(path, "w"), indent=2) +print(f"wrote {path}") +PYEOF +} + if [[ "${1:-}" == "--source" ]]; then cp "$2" "$SPEC" + OMNI_SHA="$(git -C "$(dirname "$2")" rev-parse HEAD 2>/dev/null || echo unknown)" + record_provenance "omni repo @ $OMNI_SHA" echo "synced spec from $2" elif [[ "${1:-}" == "--url" ]]; then curl -fsSL "${2%/}/openapi.json" -o "$SPEC" + record_provenance "${2%/}/openapi.json" echo "synced spec from ${2%/}/openapi.json" fi diff --git a/spec/openapi.processed.json b/spec/openapi.processed.json deleted file mode 100644 index 57c4d92..0000000 --- a/spec/openapi.processed.json +++ /dev/null @@ -1,25769 +0,0 @@ -{ - "info": { - "description": "The Omni API enables programmatic access to dashboards, documents, models, and other resources.", - "title": "Omni API", - "version": "1.0.0" - }, - "openapi": "3.1.0", - "security": [ - { - "bearerAuth": [] - } - ], - "tags": [ - { - "description": "AI-powered data analysis. Submit natural language questions as synchronous queries or asynchronous jobs, and retrieve results including generated queries, data, and summarized answers.", - "name": "AI" - }, - { - "description": "Saved AI prompts that fire on a schedule and deliver the response to email recipients.", - "name": "AI Routines" - }, - { - "description": "AI evaluation: manage prompt sets and runs used to score AI quality against curated prompt suites.", - "name": "AI Eval" - }, - { - "description": "AI-generated model suggestions: list, generate, schedule, and manage suggested improvements to a shared model.", - "name": "AI Model Suggestions" - }, - { - "description": "API token management", - "name": "API Tokens" - }, - { - "description": "Database connections and environments", - "name": "Connections" - }, - { - "description": "Content retrieval", - "name": "Content" - }, - { - "description": "Dashboard downloads and filters", - "name": "Dashboards" - }, - { - "description": "Document and workbook management", - "name": "Documents" - }, - { - "description": "Embedded SSO session management", - "name": "Embed" - }, - { - "description": "Folder organization and permissions", - "name": "Folders" - }, - { - "description": "Label management", - "name": "Labels" - }, - { - "description": "Semantic model management", - "name": "Models" - }, - { - "description": "Query execution", - "name": "Query" - }, - { - "description": "Schedule management and delivery", - "name": "Schedules" - }, - { - "description": "SCIM provisioning", - "name": "SCIM" - }, - { - "description": "Unstable API routes - subject to change", - "name": "Unstable" - }, - { - "description": "File upload management", - "name": "Uploads" - }, - { - "description": "User attribute definitions management", - "name": "User Attributes" - }, - { - "description": "User and group management", - "name": "Users" - }, - { - "description": "Self-introspection: the authenticated caller can discover their own identity, key scope, org role, and resolved per-model permissions.", - "name": "Whoami" - } - ], - "components": { - "securitySchemes": { - "bearerAuth": { - "bearerFormat": "API Token", - "description": "Include in the Authorization header as: Authorization: Bearer ", - "scheme": "bearer", - "type": "http" - } - }, - "schemas": { - "DbtEnvironmentVariableUpdate": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Existing variable ID" - }, - "isSecret": { - "type": "boolean", - "description": "Whether the variable value is secret" - }, - "value": { - "type": [ - "string", - "null" - ], - "description": "Updated variable value. Omit or set to null to keep the existing value for secret variables." - } - }, - "required": [ - "id", - "isSecret" - ], - "additionalProperties": false, - "description": "Update an existing variable by ID. Variable names cannot be changed after creation.", - "title": "DbtEnvironmentVariableUpdate" - }, - "CompositeFilter": { - "type": "object", - "properties": { - "cancel_query_filter": { - "type": "boolean" - }, - "ignore_if_unjoinable": { - "type": "boolean" - }, - "conjunction": { - "type": "string", - "enum": [ - "OR", - "AND" - ] - }, - "filters": { - "type": "array", - "items": { - "anyOf": [ - { - "type": "object", - "properties": { - "cancel_query_filter": { - "type": "boolean" - }, - "ignore_if_unjoinable": { - "type": "boolean" - }, - "appliedLabels": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "case_insensitive": { - "type": "boolean" - }, - "is_negative": { - "type": [ - "boolean", - "null" - ] - }, - "kind": { - "type": "string", - "enum": [ - "CONTAINS", - "ENDS_WITH", - "STARTS_WITH", - "EQUALS", - "IS_EMPTY", - "SQL_LIKE" - ] - }, - "type": { - "type": "string", - "enum": [ - "string" - ] - }, - "values": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "kind", - "type", - "values" - ] - }, - { - "type": "object", - "properties": { - "cancel_query_filter": { - "type": "boolean" - }, - "ignore_if_unjoinable": { - "type": "boolean" - }, - "is_inclusive": { - "type": "boolean" - }, - "is_negative": { - "type": [ - "boolean", - "null" - ] - }, - "kind": { - "type": "string", - "enum": [ - "LESS_THAN", - "GREATER_THAN", - "EQUALS", - "BETWEEN" - ] - }, - "type": { - "type": "string", - "enum": [ - "number" - ] - }, - "values": { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - } - } - }, - "required": [ - "kind", - "type", - "values" - ] - }, - { - "type": "object", - "properties": { - "cancel_query_filter": { - "type": "boolean" - }, - "ignore_if_unjoinable": { - "type": "boolean" - }, - "isFiscal": { - "type": "boolean" - }, - "is_negative": { - "type": [ - "boolean", - "null" - ] - }, - "kind": { - "type": "string", - "enum": [ - "IS_ON_DAY_OF_WEEK", - "IS_ON_DAY_OF_QUARTER", - "IS_IN_MONTH_OF_YEAR", - "IS_ON_DAY_OF_YEAR", - "IS_AT_HOUR_OF_DAY", - "IS_IN_QUARTER_OF_YEAR", - "IS_IN_WEEK_OF_YEAR", - "IS_ON_DAY_OF_MONTH", - "BETWEEN", - "ON_OR_AFTER", - "BEFORE", - "TIME_FOR_INTERVAL_DURATION", - "TIME_FOR_UNIT_DURATION", - "QUERY_OFFSET" - ] - }, - "left_side": { - "type": [ - "string", - "null" - ] - }, - "offset_interval_string": { - "type": [ - "string", - "null" - ] - }, - "right_side": { - "type": [ - "string", - "null" - ] - }, - "type": { - "type": "string", - "enum": [ - "date" - ] - }, - "ui_type": { - "type": [ - "string", - "null" - ], - "enum": [ - "ANY_TIME", - "BEFORE", - "BETWEEN", - "MONTH_OF_YEAR", - "PAST", - "YEAR", - "DAY", - "IS_ON_DAY_OF_WEEK", - "ON_OR_AFTER", - "IS_IN_THE_MONTH", - "IS_IN_THE_QUARTER", - "IS_IN_THE_FISCAL_QUARTER", - "IS_IN_THE_FISCAL_YEAR", - "TIME_FOR_INTERVAL_DURATION", - "TIME_FOR_UNIT_DURATION", - "CUSTOM", - null - ] - } - }, - "required": [ - "kind", - "type" - ] - }, - { - "type": "object", - "properties": { - "cancel_query_filter": { - "type": "boolean" - }, - "ignore_if_unjoinable": { - "type": "boolean" - }, - "is_negative": { - "type": [ - "boolean", - "null" - ] - }, - "type": { - "type": "string", - "enum": [ - "null" - ] - } - }, - "required": [ - "type" - ] - }, - { - "type": "object", - "properties": { - "cancel_query_filter": { - "type": "boolean" - }, - "ignore_if_unjoinable": { - "type": "boolean" - }, - "is_negative": { - "type": [ - "boolean", - "null" - ] - }, - "treat_nulls_as_false": { - "type": "boolean" - }, - "type": { - "type": "string", - "enum": [ - "boolean" - ] - } - }, - "required": [ - "type" - ] - }, - { - "type": "object", - "properties": { - "cancel_query_filter": { - "type": "boolean" - }, - "ignore_if_unjoinable": { - "type": "boolean" - }, - "disregard_limit": { - "type": "boolean" - }, - "field_name": { - "type": "string" - }, - "is_negative": { - "type": [ - "boolean", - "null" - ] - }, - "query_id": { - "type": "string" - }, - "type": { - "type": "string", - "enum": [ - "query" - ] - }, - "view_query": { - "type": "object", - "properties": { - "fields": { - "type": "array", - "items": { - "type": "string" - } - }, - "filters": { - "type": "object", - "additionalProperties": {}, - "default": {} - }, - "limit": { - "type": "number" - }, - "sorts": { - "type": "array", - "items": {}, - "default": [] - }, - "table": { - "type": "string" - } - }, - "required": [ - "fields" - ], - "additionalProperties": {} - } - }, - "required": [ - "type" - ] - }, - { - "type": "object", - "properties": { - "cancel_query_filter": { - "type": "boolean" - }, - "ignore_if_unjoinable": { - "type": "boolean" - }, - "type": { - "type": "string", - "enum": [ - "user_attribute" - ] - }, - "user_attribute_name": { - "type": "string" - } - }, - "required": [ - "type", - "user_attribute_name" - ] - }, - { - "$ref": "#/components/schemas/CompositeFilter" - } - ] - }, - "description": "Child filters \u2014 each a simple filter or another composite filter. Recursive; see the dashboard-filters reference for the full grammar." - }, - "is_negative": { - "type": [ - "boolean", - "null" - ] - }, - "type": { - "type": "string", - "enum": [ - "composite" - ] - } - }, - "required": [ - "conjunction", - "filters", - "type" - ] - }, - "AiGenerateQueryResponse": { - "type": "object", - "properties": { - "baseView": { - "type": [ - "string", - "null" - ], - "description": "The base view name used for query generation when queryAllViews surfaced a non-topic view. Mutually exclusive with `topic` \u2014 exactly one is non-null when a query was generated.", - "example": null - }, - "downgradedModelTier": { - "type": "string", - "description": "Present only when the organization is over its AI downgrade threshold, signaling the query was generated on a downgraded (cheaper) model tier (e.g. 'haiku') to conserve credits. Advisory and best-effort \u2014 the call still succeeds, and clients may surface that a downgraded model was used. Absent when no downgrade applied.", - "example": "haiku" - }, - "error": { - "type": [ - "object", - "null" - ], - "properties": { - "detail": { - "type": "string", - "description": "Detailed error message explaining why query generation failed.", - "example": "The AI was unable to generate a query for this prompt. Try rephrasing your question to be more specific about the data you want to retrieve." - }, - "message": { - "type": "string", - "description": "Short error summary.", - "example": "No query generated" - } - }, - "required": [ - "detail", - "message" - ], - "description": "Error details if query generation failed. Null on success." - }, - "query": { - "$ref": "#/components/schemas/AiSemanticQuery" - }, - "result": { - "type": "object", - "additionalProperties": {}, - "description": "Query execution results as a JSON object. Only present when runQuery is true (the default) and the query executed successfully. The structure contains the query result data." - }, - "topic": { - "type": [ - "string", - "null" - ], - "description": "The topic name used for query generation. Mutually exclusive with `baseView` \u2014 exactly one is non-null when a query was generated.", - "example": "order_items" - }, - "workbookUrl": { - "type": "string", - "format": "uri", - "description": "URL to view and edit the generated query in an Omni workbook. Only present when workbookUrl was set to true in the request.", - "example": "https://myorg.omni.co/w/abc123/1" - } - }, - "required": [ - "error", - "query" - ] - }, - "AiSemanticQuery": { - "type": "object", - "additionalProperties": true, - "description": "The generated semantic query definition. Null if generation failed. This query can be passed directly to the POST /api/v1/query/run endpoint. (Not statically modeled; use plain dicts.)" - }, - "AiQuerySort": { - "type": "object", - "properties": { - "column_name": { - "type": "string", - "description": "Fully qualified field name to sort by (e.g., \"view_name.field_name\").", - "example": "order_items.total_revenue" - }, - "sort_descending": { - "type": "boolean", - "description": "Whether to sort in descending order.", - "example": true - } - }, - "required": [ - "column_name", - "sort_descending" - ] - }, - "ApiError400": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Bad Request: prompt: Required" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 400 - } - }, - "required": [ - "detail", - "status" - ] - }, - "ApiError401": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Unauthorized: Missing or invalid API key" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 401 - } - }, - "required": [ - "detail", - "status" - ] - }, - "AiCreditShutoffError": { - "type": "object", - "properties": { - "code": { - "type": "string", - "enum": [ - "shutoff" - ], - "description": "Stable reason code identifying an AI-credit shutoff.", - "example": "shutoff" - }, - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "The AI credit limit has been reached. Contact your administrator for assistance." - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 402 - } - }, - "required": [ - "code", - "detail", - "status" - ] - }, - "ApiError403": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Forbidden: AI query generation is not enabled for this organization" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 403 - } - }, - "required": [ - "detail", - "status" - ] - }, - "ApiError404": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Model 770e8400-e29b-41d4-a716-446655440002 not found" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 404 - } - }, - "required": [ - "detail", - "status" - ] - }, - "AiGenerateQueryBody": { - "allOf": [ - { - "$ref": "#/components/schemas/AiTopicParams" - }, - { - "type": "object", - "properties": { - "prompt": { - "type": "string", - "description": "The natural language prompt describing the data you want to retrieve.", - "example": "Show me total revenue by month for the last year" - }, - "queryAllViews": { - "type": "boolean", - "description": "If true and the model has query_all_views_and_fields enabled, AI can query views not in any topic." - }, - "runQuery": { - "type": "boolean", - "description": "Whether to execute the generated query and return results. Defaults to true. Set to false to only generate the query definition without executing it.", - "example": true - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "User ID to execute the query as. Their permissions will be applied for row-level security. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", - "example": "990e8400-e29b-41d4-a716-446655440004" - }, - "workbookUrl": { - "type": "boolean", - "description": "If true, creates a new workbook with the generated query and returns its URL. Useful for sharing results or further exploration.", - "example": false - } - }, - "required": [ - "prompt" - ] - } - ] - }, - "AiTopicParams": { - "type": "object", - "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "currentTopicName": { - "type": "string", - "description": "The name of the current topic to scope query generation. If not provided, AI will automatically select the best topic for your prompt.", - "example": "order_items" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The UUID of the shared model to query against. Only shared models are supported.", - "example": "770e8400-e29b-41d4-a716-446655440002" - } - }, - "required": [ - "modelId" - ] - }, - "AiPickTopicResponse": { - "type": "object", - "properties": { - "topicId": { - "type": "string", - "description": "The name of the topic that best matches the prompt. Use this as the topicName parameter when calling generate-query or submitting an AI job.", - "example": "order_items" - } - }, - "required": [ - "topicId" - ] - }, - "AiPickTopicBody": { - "allOf": [ - { - "$ref": "#/components/schemas/AiTopicParams" - }, - { - "type": "object", - "properties": { - "potentialTopicNames": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Optional list of topic names to limit consideration to. If not provided, all topics the user has access to in the model will be evaluated.", - "example": [ - "order_items", - "customers", - "products" - ] - }, - "prompt": { - "type": "string", - "description": "The natural language prompt to analyze. The AI will determine which topic best matches the data described in this prompt.", - "example": "How many orders were placed last month?" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "User ID to evaluate topic access as. Their permissions will be used for permission-aware topic selection. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", - "example": "990e8400-e29b-41d4-a716-446655440004" - } - }, - "required": [ - "prompt" - ] - } - ] - }, - "AiSearchOmniDocsResponse": { - "type": "object", - "properties": { - "answer": { - "type": "string", - "description": "A synthesized answer to the question, based on the Omni documentation.", - "example": "To create a dashboard filter, navigate to your dashboard and click the \"Add Filter\" button..." - }, - "sources": { - "type": "array", - "items": { - "type": "object", - "properties": { - "title": { - "type": "string", - "description": "The title of the source documentation page.", - "example": "Dashboard Filters" - }, - "url": { - "type": "string", - "format": "uri", - "description": "URL of the source documentation page.", - "example": "https://docs.omni.co/docs/dashboards/filters" - } - }, - "required": [ - "title", - "url" - ] - }, - "description": "List of documentation pages that were used to synthesize the answer." - } - }, - "required": [ - "answer", - "sources" - ] - }, - "AiSearchOmniDocsBody": { - "type": "object", - "properties": { - "question": { - "type": "string", - "minLength": 1, - "maxLength": 2000, - "description": "A natural language question about Omni features, configuration, modeling, dashboards, or other topics covered in the Omni documentation.", - "example": "How do I create a dashboard filter?" - } - }, - "required": [ - "question" - ] - }, - "AiJobSubmitResponse": { - "type": "object", - "properties": { - "conversationId": { - "type": "string", - "format": "uuid", - "description": "The conversation ID for this job. Pass this as conversationId in subsequent job submissions to continue the conversation with additional context.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "jobId": { - "type": "string", - "format": "uuid", - "description": "The unique identifier for the created job. Use this to poll status via GET /api/v1/ai/jobs/{jobId} or retrieve results via GET /api/v1/ai/jobs/{jobId}/result.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "omniChatUrl": { - "type": "string", - "format": "uri", - "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", - "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" - } - }, - "required": [ - "conversationId", - "jobId", - "omniChatUrl" - ] - }, - "ApiError409": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "An active job already exists for this conversation" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 409 - } - }, - "required": [ - "detail", - "status" - ] - }, - "AiJobSubmitBody": { - "type": "object", - "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId. Use this to query against in-progress model changes.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "conversationId": { - "type": "string", - "format": "uuid", - "description": "Conversation ID to continue an existing conversation thread. The AI will have access to the context from previous jobs in the same conversation. If omitted, a new conversation is created. Only one active job can exist per conversation.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The UUID of the model to query against. Must be a shared model, or a shared-extension model usable as a workbook base.", - "example": "770e8400-e29b-41d4-a716-446655440002" - }, - "progressWebhookEnabled": { - "type": "boolean", - "default": false, - "description": "When true, real-time progress events are POSTed to webhookUrl during execution (e.g., \"Searching for revenue fields\", \"Query returned 42 rows\"). Requires webhookUrl. Progress events are best-effort: single attempt, no retries, failures do not affect job execution.", - "example": true - }, - "prompt": { - "type": "string", - "minLength": 1, - "description": "The natural language prompt for the AI to process. The AI will analyze your question, generate appropriate queries, execute them, and return a summarized answer.", - "example": "What are the top 5 products by revenue this quarter?" - }, - "topicName": { - "type": "string", - "maxLength": 256, - "description": "Topic name to scope query generation. Topics define a set of related views and their join paths. If not provided, the AI will automatically select the best topic. Use the pick-topic endpoint to determine the right topic programmatically.", - "example": "order_items" - }, - "webhookMetadata": { - "type": "object", - "additionalProperties": {}, - "description": "Arbitrary metadata object that will be included unchanged in webhook payloads. Use this to correlate webhook notifications with your own system (e.g., tracking IDs, channel references).", - "example": { - "externalId": "task-123", - "slackChannel": "C0123456789" - } - }, - "webhookSigningSecret": { - "type": "string", - "description": "Secret key for HMAC-SHA256 webhook payload signing. When provided, each webhook request includes X-Omni-Signature and X-Omni-Signature-Timestamp headers for verification. Required if webhookUrl is specified." - }, - "webhookUrl": { - "type": "string", - "format": "uri", - "description": "URL to receive webhook POSTs. Always receives a terminal event (job.complete, job.failed, or job.denied) when the job finishes; a job.denied event (e.g. the organization is over its AI credit limit) additionally carries a reason field. When progressWebhookEnabled is true, also receives real-time progress events during execution.", - "example": "https://example.com/webhooks/omni" - } - }, - "required": [ - "modelId", - "prompt" - ] - }, - "AiJobStatusResponse": { - "type": "object", - "properties": { - "branchId": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Branch ID used for model context, or null if querying the main shared model." - }, - "cancelledAt": { - "type": "string", - "format": "date-time", - "description": "When the job was cancelled. Only present in CANCELLED state.", - "example": "2025-01-15T10:00:12.000Z" - }, - "cancelledBy": { - "type": "string", - "format": "uuid", - "description": "User ID of who cancelled the job. Only present in CANCELLED state.", - "example": "990e8400-e29b-41d4-a716-446655440004" - }, - "completedAt": { - "type": "string", - "format": "date-time", - "description": "When the job finished (successfully or with error). Present in COMPLETE and FAILED states.", - "example": "2025-01-15T10:01:30.000Z" - }, - "conversationId": { - "type": "string", - "format": "uuid", - "description": "The conversation this job belongs to. Use this to submit follow-up jobs in the same conversation thread.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "createdAt": { - "type": "string", - "format": "date-time", - "description": "When the job was submitted.", - "example": "2025-01-15T10:00:00.000Z" - }, - "error": { - "type": "object", - "properties": { - "code": { - "type": "string", - "description": "Machine-readable error code.", - "example": "QUERY_EXECUTION_ERROR" - }, - "detail": { - "type": "string", - "description": "Additional error detail or context.", - "example": "The query timed out after 300 seconds" - }, - "message": { - "type": "string", - "description": "Human-readable error message.", - "example": "Column 'revenue' not found in table 'orders'" - } - }, - "required": [ - "message" - ], - "additionalProperties": {}, - "description": "Error details explaining why the job failed. Only present in FAILED state." - }, - "executionStartedAt": { - "type": "string", - "format": "date-time", - "description": "When execution began. Present once the job transitions from QUEUED to EXECUTING. May be absent on jobs that failed or were cancelled before execution started.", - "example": "2025-01-15T10:00:05.000Z" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "The unique identifier for this job.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "modelId": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "The shared model ID used for query generation.", - "example": "770e8400-e29b-41d4-a716-446655440002" - }, - "omniChatUrl": { - "type": "string", - "format": "uri", - "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", - "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" - }, - "organizationId": { - "type": "string", - "format": "uuid", - "description": "The organization that owns this job.", - "example": "880e8400-e29b-41d4-a716-446655440003" - }, - "progress": { - "type": [ - "object", - "null" - ], - "properties": { - "iteration": { - "type": "integer", - "description": "Current iteration number. The AI may take multiple iterations to refine queries and generate a complete answer.", - "example": 2 - }, - "message": { - "type": "string", - "description": "Human-readable status message describing what the AI is currently doing.", - "example": "Running query: Top products by revenue" - }, - "updatedAt": { - "type": "string", - "format": "date-time", - "description": "When this progress update was recorded.", - "example": "2025-01-15T10:00:08.000Z" - } - }, - "required": [ - "iteration", - "message", - "updatedAt" - ], - "description": "Real-time progress information. Only present in EXECUTING state. Null if no progress has been reported yet. Updated in real-time as the AI works through iterations." - }, - "prompt": { - "type": "string", - "description": "The natural language prompt that was submitted.", - "example": "What are the top 5 products by revenue?" - }, - "resultSummary": { - "type": "string", - "description": "Markdown-formatted summary of the job result. Only present in COMPLETE state. For the full result with query details and data, use GET /api/v1/ai/jobs/{jobId}/result.", - "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" - }, - "state": { - "type": "string", - "enum": [ - "CANCELLED", - "COMPLETE", - "DELIVERING", - "EXECUTING", - "FAILED", - "QUEUED" - ], - "description": "Current state of the job. Terminal states are COMPLETE, FAILED, and CANCELLED. Poll until the job reaches a terminal state.", - "example": "QUEUED" - }, - "topicName": { - "type": [ - "string", - "null" - ], - "description": "Topic name used to scope query generation, or null if the AI selected the topic automatically.", - "example": "order_items" - }, - "updatedAt": { - "type": "string", - "format": "date-time", - "description": "When the job record was last modified.", - "example": "2025-01-15T10:00:05.000Z" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "The user ID who created (or is associated with) this job.", - "example": "990e8400-e29b-41d4-a716-446655440004" - } - }, - "required": [ - "branchId", - "conversationId", - "createdAt", - "id", - "modelId", - "omniChatUrl", - "organizationId", - "prompt", - "state", - "topicName", - "updatedAt", - "userId" - ] - }, - "AiJobCancelResponse": { - "type": "object", - "properties": { - "jobId": { - "type": "string", - "format": "uuid", - "description": "The job ID that was requested to cancel.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "state": { - "type": "string", - "enum": [ - "CANCELLED", - "COMPLETE", - "DELIVERING", - "EXECUTING", - "FAILED", - "QUEUED" - ], - "description": "The job state after the cancellation attempt. CANCELLED if the cancellation was successful. If the job was already in a terminal state (COMPLETE, FAILED, CANCELLED), the current state is returned unchanged \u2014 the endpoint is idempotent.", - "example": "CANCELLED" - } - }, - "required": [ - "jobId", - "state" - ] - }, - "AiJobResultResponse": { - "type": "object", - "properties": { - "actions": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AiJobAction" - }, - "description": "Ordered list of actions the AI took during execution. Each action represents a step such as generating a query, executing it, or synthesizing a final answer." - }, - "message": { - "type": "string", - "description": "The AI's final response message in Markdown format. This is the complete answer to the original prompt, incorporating data from all executed queries.", - "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" - }, - "omniChatUrl": { - "type": "string", - "format": "uri", - "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", - "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" - }, - "resultSummary": { - "type": "string", - "description": "Summary of the job result. Typically matches the final message content.", - "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" - }, - "topic": { - "type": "string", - "description": "The topic name used for query generation.", - "example": "order_items" - } - }, - "additionalProperties": {} - }, - "AiJobAction": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "The AI's explanation of what it is doing in this step, written in natural language.", - "example": "I'll generate a query to find the top 5 products by total revenue." - }, - "result": { - "$ref": "#/components/schemas/AiJobActionQueryResult" - }, - "timestamp": { - "type": "string", - "description": "ISO 8601 timestamp when this action occurred.", - "example": "2025-01-15T10:00:10.000Z" - }, - "type": { - "type": "string", - "description": "The type of action. Common types include \"generate_query\" (query generation and execution) and \"summarize\" (final answer synthesis).", - "example": "generate_query" - } - }, - "required": [ - "message", - "timestamp", - "type" - ], - "additionalProperties": {} - }, - "AiJobActionQueryResult": { - "type": "object", - "properties": { - "csvResult": { - "type": "string", - "description": "Query results formatted as CSV text.", - "example": "Name,Total Revenue\nRay-Ban Sunglasses,\"678,994.41\"\nLevi's 501 Jeans,\"475,072.00\"" - }, - "csvResultWasTruncated": { - "type": "boolean", - "description": "Whether the CSV data was truncated due to size limits. If true, the full result set may contain additional rows not included in csvResult.", - "example": false - }, - "hasResults": { - "type": "boolean", - "description": "Whether the query returned any data rows.", - "example": true - }, - "query": { - "type": "object", - "additionalProperties": {}, - "description": "The semantic query definition that was executed. This can be used with the POST /api/v1/query/run endpoint to re-run the query." - }, - "queryName": { - "type": "string", - "description": "Human-readable name describing what this query retrieves.", - "example": "Top 5 Products by Revenue" - }, - "resultId": { - "type": "string", - "description": "Stable, unique identifier for this query result within the job. Use it to reference a specific result \u2014 for example, to correlate or de-duplicate results across responses.", - "example": "928c5838-000d-4943-b305-f6242c1b4922" - }, - "status": { - "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Whether the query executed successfully.", - "example": "success" - }, - "totalRowCount": { - "type": "integer", - "description": "Total number of rows returned by the query.", - "example": 5 - } - }, - "required": [ - "csvResult", - "csvResultWasTruncated", - "hasResults", - "query", - "queryName", - "status", - "totalRowCount" - ], - "description": "Query result data. Only present for generate_query action types." - }, - "ApiError422": { - "type": "object", - "properties": { - "error": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "No Arrow IPC data available for visualization" - } - }, - "required": [ - "error" - ] - }, - "AiBrandingResponse": { - "type": "object", - "properties": { - "body": { - "type": "string", - "description": "Body / description copy shown beneath the headline on AI helper landing surfaces.", - "example": "I can help answer data questions, build a Dashboard, or create an App." - }, - "headline": { - "type": "string", - "description": "Short headline shown on AI helper landing surfaces.", - "example": "What would you like to know?" - }, - "logoUrl": { - "type": [ - "string", - "null" - ], - "format": "uri", - "description": "Absolute URL to a custom AI helper logo. `null` when the org has not configured a custom logo \u2014 clients should render their default avatar (e.g. Blobby).", - "example": "https://example.com/blobby.png" - }, - "name": { - "type": "string", - "description": "Display name for the AI helper. Defaults to `Omni Agent` when no custom branding is set.", - "example": "Blobby" - }, - "placeholder": { - "type": "string", - "description": "Placeholder text for the AI helper's prompt input.", - "example": "Ask a question about your data..." - } - }, - "required": [ - "body", - "headline", - "logoUrl", - "name", - "placeholder" - ] - }, - "AiConversationsListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AiConversation" - }, - "description": "Conversations ordered by updatedAt descending." - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "PageInfo": { - "type": "object", - "properties": { - "hasNextPage": { - "type": "boolean", - "description": "Whether more results are available" - }, - "nextCursor": { - "type": [ - "string", - "null" - ], - "description": "Cursor for fetching the next page" - }, - "pageSize": { - "type": "number", - "description": "Number of results per page" - }, - "totalRecords": { - "type": "number", - "description": "Total number of records matching the query" - } - }, - "required": [ - "hasNextPage", - "nextCursor", - "pageSize", - "totalRecords" - ] - }, - "AiConversation": { - "type": "object", - "properties": { - "createdAt": { - "type": "string", - "format": "date-time", - "description": "When the conversation was started.", - "example": "2025-01-15T10:00:00.000Z" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Conversation ID. Pass as conversationId on subsequent /api/v1/ai/jobs submissions to continue this conversation.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "lastPrompt": { - "type": [ - "string", - "null" - ], - "description": "The most recent user prompt in this conversation, useful for displaying a one-line summary in a list.", - "example": "What were our top products last week?" - }, - "name": { - "type": [ - "string", - "null" - ], - "description": "Conversation title. Set by the AI after the first turn; null on brand-new sessions.", - "example": "Top products last week" - }, - "updatedAt": { - "type": "string", - "format": "date-time", - "description": "When the conversation was last touched (most recent prompt or AI activity).", - "example": "2025-01-15T10:01:30.000Z" - } - }, - "required": [ - "createdAt", - "id", - "lastPrompt", - "name", - "updatedAt" - ] - }, - "AiConversationDetailResponse": { - "type": "object", - "properties": { - "createdAt": { - "type": "string", - "format": "date-time" - }, - "id": { - "type": "string", - "format": "uuid" - }, - "messages": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AiConversationMessage" - }, - "description": "Messages in chronological order. Alternating user / assistant turns." - }, - "name": { - "type": [ - "string", - "null" - ] - }, - "updatedAt": { - "type": "string", - "format": "date-time" - } - }, - "required": [ - "createdAt", - "id", - "messages", - "name", - "updatedAt" - ] - }, - "AiConversationMessage": { - "type": "object", - "properties": { - "createdAt": { - "type": "string", - "format": "date-time", - "description": "When this turn was recorded.", - "example": "2025-01-15T10:00:00.000Z" - }, - "jobId": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "The agentic job that produced this assistant turn. Only set for assistant messages \u2014 clients use it to fetch the rendered chart via GET /api/v1/ai/jobs/{jobId}/vis. Null when the turn predates jobs or when we could not associate one.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "omniChatUrl": { - "type": [ - "string", - "null" - ], - "format": "uri", - "description": "Deep link to the assistant turn in the Omni chat UI. Null for user turns, and for assistant turns produced outside the Agentic API (where no AgenticJob row exists).", - "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" - }, - "role": { - "type": "string", - "enum": [ - "user", - "assistant" - ], - "description": "Speaker \u2014 `user` for prompts the user submitted, `assistant` for Blobby's responses.", - "example": "user" - }, - "text": { - "type": "string", - "description": "Markdown content of the message. For assistant turns this is the same string returned by /api/v1/ai/jobs/{jobId}/result#message.", - "example": "What were our top products last week?" - } - }, - "required": [ - "createdAt", - "jobId", - "omniChatUrl", - "role", - "text" - ] - }, - "AiCreditControlsResponse": { - "type": "object", - "properties": { - "accountCreditLimit": { - "type": "number", - "minimum": 0, - "description": "Monthly AI credit limit for the whole Omni account (shared across every org under the same Salesforce account), not just this org. 0 when no limit is configured.", - "example": 2000 - }, - "creditsUsed": { - "type": "number", - "minimum": 0, - "description": "This org's credit usage in the current billing period.", - "example": 450 - }, - "downgradeCredits": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "description": "Downgrade threshold, or `null` if the downgrade control is off.", - "example": 800 - }, - "periodEnd": { - "type": "integer", - "minimum": 0, - "description": "End of the current billing period as a Unix ms timestamp (UTC calendar-month boundary)." - }, - "periodStart": { - "type": "integer", - "minimum": 0, - "description": "Start of the current billing period as a Unix ms timestamp (UTC calendar-month boundary)." - }, - "shutoffCredits": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "description": "Shutoff threshold, or `null` if the shutoff control is off.", - "example": 1200 - }, - "userDefaultCredits": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "description": "Default per-user AI credit limit, or `null` when users are unlimited by default.", - "example": 100 - } - }, - "required": [ - "accountCreditLimit", - "creditsUsed", - "downgradeCredits", - "periodEnd", - "periodStart", - "shutoffCredits", - "userDefaultCredits" - ] - }, - "AiCreditControlsUpdateBody": { - "type": "object", - "properties": { - "downgradeCredits": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "description": "Credit usage at which AI downgrades to a cheaper model. Omit to leave unchanged, `null` to turn off, or a non-negative number to set. Must be at or below shutoffCredits.", - "example": 800 - }, - "shutoffCredits": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "description": "Credit usage at which AI shuts off entirely. Omit to leave unchanged, `null` to turn off, or a non-negative number to set.", - "example": 1200 - }, - "userDefaultCredits": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "description": "Default per-user AI credit limit for the billing period \u2014 what every user without an individual limit gets. Omit to leave unchanged, `null` for unlimited by default, or a non-negative number to set.", - "example": 100 - } - }, - "additionalProperties": false - }, - "AiCreditControlsUsersListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "type": "object", - "properties": { - "creditLimit": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "description": "The user's individual AI credit limit, or `null` for an explicit unlimited override.", - "example": 50 - }, - "userId": { - "type": "string", - "description": "The user's id within this organization.", - "example": "f4a2b3c8-0d1e-4f5a-9b6c-7d8e9f0a1b2c" - } - }, - "required": [ - "creditLimit", - "userId" - ] - }, - "description": "Users with an individual AI credit limit, ordered by userId ascending." - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "AiUserCreditLimitsResponse": { - "type": "object", - "properties": { - "users": { - "type": "array", - "items": { - "type": "object", - "properties": { - "creditLimit": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "description": "The user's effective AI credit limit, or `null` for unlimited.", - "example": 50 - }, - "userId": { - "type": "string", - "description": "The user's id within this organization.", - "example": "f4a2b3c8-0d1e-4f5a-9b6c-7d8e9f0a1b2c" - }, - "usesDefaultLimit": { - "type": "boolean", - "description": "True when the user has no individual limit and follows the org default." - } - }, - "required": [ - "creditLimit", - "userId", - "usesDefaultLimit" - ] - } - } - }, - "required": [ - "users" - ] - }, - "AiUserCreditLimitsUpdateBody": { - "type": "object", - "properties": { - "users": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AiUserCreditLimitEntry" - }, - "minItems": 1, - "maxItems": 1000, - "description": "Users to update, at most 1000 per request. Each entry has a `userId` plus exactly one of `creditLimit` (number or `null`) or `useDefaultLimit: true`." - } - }, - "required": [ - "users" - ], - "additionalProperties": false - }, - "AiUserCreditLimitEntry": { - "type": "object", - "properties": { - "creditLimit": { - "type": [ - "number", - "null" - ], - "minimum": 0, - "description": "The user's individual AI credit limit for the billing period, or `null` for unlimited. Either way this overrides the org default. Mutually exclusive with `useDefaultLimit`.", - "example": 50 - }, - "useDefaultLimit": { - "type": "boolean", - "enum": [ - true - ], - "description": "Removes the user's individual limit so they follow the org default. Mutually exclusive with `creditLimit`." - }, - "userId": { - "type": "string", - "description": "The user's id within this organization.", - "example": "f4a2b3c8-0d1e-4f5a-9b6c-7d8e9f0a1b2c" - } - }, - "required": [ - "userId" - ], - "additionalProperties": false - }, - "RoutinesListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RoutineResponse" - }, - "description": "Routines returned for this request, newest first." - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "RoutineResponse": { - "type": "object", - "properties": { - "branchId": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Branch of the shared model the prompt runs against, or null." - }, - "createdAt": { - "type": "string", - "description": "ISO 8601 timestamp when the routine was created." - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Display-only notes about the routine, or null." - }, - "destination": { - "$ref": "#/components/schemas/RoutineDestinationResponse" - }, - "disabled": { - "type": "boolean", - "description": "Whether the owner has paused the routine." - }, - "id": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the routine." - }, - "lastRun": { - "$ref": "#/components/schemas/RoutineLastRun" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The shared model the prompt runs against." - }, - "name": { - "type": "string", - "description": "Customer-visible name of the routine. Used as the email subject for email destinations, and shown on Slack deliveries." - }, - "prompt": { - "type": "string", - "description": "Natural language prompt Omni runs on each scheduled run." - }, - "recipientCount": { - "type": "integer", - "description": "Number of distinct deliverable recipients. For email, user groups are expanded to members and duplicates removed; a Slack routine is always 1 (its single channel or DM)." - }, - "schedule": { - "type": "string", - "description": "Six-field cron expression (minute, hour, day-of-month, month, day-of-week, year; use `?` for an unspecified day field)." - }, - "systemDisabled": { - "type": "boolean", - "description": "Whether Omni disabled the routine because it could no longer run successfully or safely." - }, - "systemDisabledReason": { - "type": [ - "string", - "null" - ], - "description": "Reason Omni disabled the routine, or null." - }, - "timezone": { - "type": "string", - "description": "IANA timezone identifier used to evaluate the schedule." - }, - "topicName": { - "type": [ - "string", - "null" - ], - "description": "Topic scoping query generation, or null." - }, - "updatedAt": { - "type": "string", - "description": "ISO 8601 timestamp when the routine was last updated." - } - }, - "required": [ - "branchId", - "createdAt", - "description", - "destination", - "disabled", - "id", - "lastRun", - "modelId", - "name", - "prompt", - "recipientCount", - "schedule", - "systemDisabled", - "systemDisabledReason", - "timezone", - "topicName", - "updatedAt" - ] - }, - "RoutineDestinationResponse": { - "oneOf": [ - { - "$ref": "#/components/schemas/RoutineEmailDestinationResponse" - }, - { - "$ref": "#/components/schemas/RoutineSlackDestination" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "email": "#/components/schemas/RoutineEmailDestinationResponse", - "slack": "#/components/schemas/RoutineSlackDestination" - } - }, - "description": "Delivery configuration for the routine." - }, - "RoutineEmailDestinationResponse": { - "type": "object", - "properties": { - "recipientEmails": { - "type": "array", - "items": { - "type": "string", - "format": "email" - }, - "description": "Email addresses configured as direct recipients of each scheduled run, resolved from their current membership.", - "example": [ - "alice@example.com", - "bob@example.com" - ] - }, - "type": { - "type": "string", - "enum": [ - "email" - ], - "description": "Selects email delivery \u2014 each scheduled run is sent to the listed email recipients and user groups.", - "example": "email" - }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "description": "User group IDs whose active members receive each scheduled run. Omni expands each group to the members' current email addresses when the routine runs.", - "example": [ - "550e8400-e29b-41d4-a716-446655440000" - ] - } - }, - "required": [ - "recipientEmails", - "type", - "userGroupIds" - ], - "additionalProperties": false - }, - "RoutineSlackDestination": { - "type": "object", - "properties": { - "recipientId": { - "type": "string", - "minLength": 1, - "description": "The Slack channel ID (e.g. \"C01234567\") or user ID (e.g. \"U01234567\") that receives each scheduled run. Exactly one recipient per Slack routine.", - "example": "C01234567" - }, - "slackRecipientType": { - "type": "string", - "enum": [ - "channel", - "users" - ], - "description": "Whether `recipientId` is a Slack channel or a user (delivered as a direct message).", - "example": "channel" - }, - "type": { - "type": "string", - "enum": [ - "slack" - ], - "description": "Selects Slack delivery \u2014 each scheduled run is posted to one Slack channel or sent as a direct message to one user.", - "example": "slack" - } - }, - "required": [ - "recipientId", - "slackRecipientType", - "type" - ], - "additionalProperties": false - }, - "RoutineLastRun": { - "type": [ - "object", - "null" - ], - "properties": { - "completedAt": { - "type": [ - "string", - "null" - ], - "description": "ISO 8601 timestamp the last completed run finished." - }, - "label": { - "type": "string", - "description": "Customer-visible status of the last completed run.", - "example": "Delivered" - }, - "state": { - "type": "string", - "description": "Machine-readable status of the last completed run.", - "example": "COMPLETE" - } - }, - "required": [ - "completedAt", - "label", - "state" - ], - "description": "Most recent completed run, or null if the routine has never completed a run." - }, - "RoutineCreateResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "The unique identifier for the newly created routine.", - "example": "880e8400-e29b-41d4-a716-446655440003" - } - }, - "required": [ - "id" - ] - }, - "ApiError429": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "User has reached the maximum of 100 routines" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 429 - } - }, - "required": [ - "detail", - "status" - ] - }, - "RoutineCreateBody": { - "type": "object", - "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "description": { - "type": "string", - "maxLength": 2000, - "description": "Optional human-readable notes about the routine. Display-only \u2014 never used as model input.", - "example": "Weekly signups summary for the growth team." - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The UUID of the shared model the prompt runs against. Only shared models are supported.", - "example": "770e8400-e29b-41d4-a716-446655440002" - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 512, - "description": "Customer-visible name of the routine. Used as the email subject for email destinations, and shown on Slack deliveries.", - "example": "Weekly user signups" - }, - "prompt": { - "type": "string", - "minLength": 1, - "description": "Natural language prompt Omni runs on each scheduled run.", - "example": "How many users signed up last week?" - }, - "schedule": { - "type": "string", - "minLength": 1, - "description": "Six-field cron expression (minute, hour, day-of-month, month, day-of-week, year; use `?` for an unspecified day field). Minimum frequency is once per hour; contact Omni support if you need more frequent scheduling.", - "example": "0 9 ? * MON *" - }, - "timezone": { - "type": "string", - "minLength": 1, - "description": "IANA timezone identifier used to evaluate the schedule.", - "example": "America/New_York" - }, - "topicName": { - "type": "string", - "maxLength": 256, - "description": "Topic name to scope query generation. If omitted, the AI picks the best topic.", - "example": "users" - }, - "destination": { - "$ref": "#/components/schemas/RoutineDestination" - } - }, - "required": [ - "modelId", - "name", - "prompt", - "schedule", - "timezone", - "destination" - ], - "additionalProperties": false - }, - "RoutineDestination": { - "oneOf": [ - { - "$ref": "#/components/schemas/RoutineEmailDestination" - }, - { - "$ref": "#/components/schemas/RoutineSlackDestination" - } - ], - "discriminator": { - "propertyName": "type", - "mapping": { - "email": "#/components/schemas/RoutineEmailDestination", - "slack": "#/components/schemas/RoutineSlackDestination" - } - }, - "description": "Single delivery destination for the routine. To send results to multiple destinations, create one routine per destination. Omni runs the prompt once per scheduled run using the routine owner's permissions, and every recipient receives the same result regardless of their own permissions." - }, - "RoutineEmailDestination": { - "type": "object", - "properties": { - "recipientEmails": { - "type": "array", - "items": { - "type": "string", - "format": "email" - }, - "maxItems": 100, - "default": [], - "description": "Email addresses that receive each scheduled run of the routine.", - "example": [ - "alice@example.com", - "bob@example.com" - ] - }, - "type": { - "type": "string", - "enum": [ - "email" - ], - "description": "Selects email delivery \u2014 each scheduled run is sent to the listed email recipients and user groups.", - "example": "email" - }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "maxItems": 100, - "default": [], - "description": "User group IDs whose active members receive each scheduled run. Omni expands each group to the members' current email addresses when the routine runs.", - "example": [ - "550e8400-e29b-41d4-a716-446655440000" - ] - } - }, - "required": [ - "type" - ], - "additionalProperties": false - }, - "RoutineUpdateBody": { - "type": "object", - "properties": { - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 2000, - "description": "Display-only notes about the routine. Pass null to clear it." - }, - "destination": { - "$ref": "#/components/schemas/RoutineDestination" - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 512, - "description": "New customer-visible name of the routine. Used as the email subject for email destinations, and shown on Slack deliveries." - }, - "prompt": { - "type": "string", - "minLength": 1, - "description": "New natural language prompt Omni runs on each scheduled run." - }, - "schedule": { - "type": "string", - "minLength": 1, - "description": "New six-field cron expression (minute, hour, day-of-month, month, day-of-week, year; use `?` for an unspecified day field). Minimum frequency is once per hour." - }, - "timezone": { - "type": "string", - "minLength": 1, - "description": "New IANA timezone identifier used to evaluate the schedule." - } - }, - "additionalProperties": false - }, - "RoutineDeleteResponse": { - "type": "object", - "properties": { - "deleted": { - "type": "boolean", - "enum": [ - true - ], - "description": "Always true on a successful delete." - }, - "id": { - "type": "string", - "format": "uuid", - "description": "The deleted routine\u2019s ID." - } - }, - "required": [ - "deleted", - "id" - ] - }, - "RoutineTriggerResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "The ID of the run (scheduled job) that was started.", - "example": "990e8400-e29b-41d4-a716-446655440004" - } - }, - "required": [ - "id" - ] - }, - "ApiKeyListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApiKey" - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "ApiKey": { - "type": "object", - "properties": { - "createdAt": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp of when the token was created", - "example": "2026-01-15T10:00:00.000Z" - }, - "enabled": { - "type": "boolean", - "description": "Whether the token can currently authenticate. A disabled token cannot authenticate but remains visible until deleted.", - "example": true - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the token", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "membershipId": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Membership ID of the user the token is scoped to. Null for organization-level tokens.", - "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" - }, - "name": { - "type": "string", - "description": "Human-readable name for the token", - "example": "CI deployment key" - }, - "type": { - "type": "string", - "enum": [ - "organization", - "personal", - "mcp" - ], - "description": "Token type: `organization` (org-level), `personal` (user-created personal access token), or `mcp` (MCP OAuth grant).", - "example": "organization" - } - }, - "required": [ - "createdAt", - "enabled", - "id", - "membershipId", - "name", - "type" - ] - }, - "ApiKeyUpdateBody": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Set to `false` to disable the token, `true` to re-enable it.", - "example": false - } - }, - "required": [ - "enabled" - ], - "additionalProperties": false - }, - "ApiKeyDeleteResponse": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Human-readable description of the outcome", - "example": "API token revoked" - }, - "success": { - "type": "boolean", - "enum": [ - true - ], - "description": "Always `true` on a successful revocation" - } - }, - "required": [ - "message", - "success" - ] - }, - "DbtEnvironmentListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DbtEnvironmentItem" - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "DbtEnvironmentItem": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Unique environment identifier" - }, - "isDefaultEnvironment": { - "type": "boolean", - "description": "Whether this is the default environment" - }, - "isDeferralEnabled": { - "type": "boolean", - "description": "Whether dbt deferral is enabled for this environment. Always false for the default (production) environment \u2014 the backend rejects enabling it there." - }, - "name": { - "type": "string", - "description": "Environment name" - }, - "ownerId": { - "type": [ - "string", - "null" - ], - "description": "User ID of the environment owner, or null if not a personal environment" - }, - "targetDatabase": { - "type": [ - "string", - "null" - ], - "description": "Target database override" - }, - "targetName": { - "type": [ - "string", - "null" - ], - "description": "Target name override" - }, - "targetRole": { - "type": [ - "string", - "null" - ], - "description": "Target role override" - }, - "targetSchema": { - "type": "string", - "description": "Target schema" - }, - "variables": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DbtEnvironmentResponseVariable" - }, - "description": "Environment variables" - } - }, - "required": [ - "id", - "isDefaultEnvironment", - "isDeferralEnabled", - "name", - "ownerId", - "targetDatabase", - "targetName", - "targetRole", - "targetSchema", - "variables" - ] - }, - "DbtEnvironmentResponseVariable": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Variable ID" - }, - "isSecret": { - "type": "boolean", - "description": "Whether the variable value is secret" - }, - "name": { - "type": "string", - "description": "Variable name" - }, - "value": { - "type": [ - "string", - "null" - ], - "description": "Variable value (null for secret variables)" - } - }, - "required": [ - "id", - "isSecret", - "name", - "value" - ] - }, - "DbtEnvironmentCreateBody": { - "type": "object", - "properties": { - "isDeferralEnabled": { - "type": "boolean", - "default": false, - "description": "Whether to enable dbt deferral for this environment. Ignored (forced to false) for the default (production) environment.", - "example": false - }, - "name": { - "type": "string", - "minLength": 1, - "description": "Environment name", - "example": "PR_1111_Expose" - }, - "ownerId": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", - "example": null - }, - "targetDatabase": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "Target database override", - "example": "analytics_dev" - }, - "targetName": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "Target name override", - "example": null - }, - "targetRole": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "Target role override", - "example": null - }, - "targetSchema": { - "type": "string", - "minLength": 1, - "description": "Target schema for this environment", - "example": "PR_1111_Expose" - }, - "variables": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DbtEnvironmentVariable" - }, - "default": [], - "description": "Environment variables" - } - }, - "required": [ - "name", - "targetSchema" - ] - }, - "DbtEnvironmentVariable": { - "type": "object", - "properties": { - "isSecret": { - "type": "boolean", - "description": "Whether the variable value is secret" - }, - "name": { - "type": "string", - "minLength": 1, - "description": "Variable name" - }, - "value": { - "type": "string", - "description": "Variable value" - } - }, - "required": [ - "isSecret", - "name", - "value" - ] - }, - "DbtEnvironmentUpdateBody": { - "type": "object", - "properties": { - "isDeferralEnabled": { - "type": "boolean", - "default": false, - "description": "Whether to enable dbt deferral for this environment. Ignored (forced to false) for the default (production) environment.", - "example": false - }, - "name": { - "type": "string", - "minLength": 1, - "description": "Environment name", - "example": "PR_1111_Expose" - }, - "ownerId": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", - "example": null - }, - "targetDatabase": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "Target database override", - "example": "analytics_dev" - }, - "targetName": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "Target name override", - "example": null - }, - "targetRole": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "Target role override", - "example": null - }, - "targetSchema": { - "type": "string", - "minLength": 1, - "description": "Target schema for this environment", - "example": "PR_1111_Expose" - }, - "variables": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DbtEnvironmentVariableUpdateOrNew" - }, - "default": [], - "description": "Environment variables. Variables with an id update existing ones; variables without an id create new ones." - } - }, - "required": [ - "name", - "targetSchema" - ] - }, - "DbtEnvironmentVariableUpdateOrNew": { - "oneOf": [ - { - "$ref": "#/components/schemas/DbtEnvironmentVariableUpdate" - }, - { - "$ref": "#/components/schemas/DbtEnvironmentVariable" - } - ] - }, - "DbtEnvironmentDeleteResponse": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Confirmation message", - "example": "dbt environment deleted successfully" - }, - "success": { - "type": "boolean", - "description": "Whether the deletion was successful", - "example": true - } - }, - "required": [ - "message", - "success" - ] - }, - "ContentListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "oneOf": [ - { - "allOf": [ - { - "$ref": "#/components/schemas/ApiDocument" - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "document" - ] - } - }, - "required": [ - "type" - ] - } - ] - }, - { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier" - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Content name" - }, - "owner": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "User ID of the owner" - }, - "name": { - "type": "string", - "description": "Name of the owner" - } - }, - "required": [ - "id", - "name" - ], - "description": "Content owner" - }, - "scope": { - "type": "string", - "enum": [ - "restricted", - "organization" - ], - "description": "Content access scope" - }, - "_count": { - "type": "object", - "properties": { - "documents": { - "type": "number", - "description": "Number of documents" - }, - "favorites": { - "type": "number", - "description": "Number of users who favorited" - } - }, - "required": [ - "documents", - "favorites" - ], - "description": "Folder counts" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels" - }, - "path": { - "type": "string", - "description": "Full path to the folder", - "example": "sales-reports/q1-2026" - }, - "url": { - "type": "string", - "description": "URL to view the folder in the Omni UI.", - "example": "https://org.omni.co/f/sales-reports" - }, - "type": { - "type": "string", - "enum": [ - "folder" - ] - } - }, - "required": [ - "id", - "name", - "owner", - "scope", - "path", - "url", - "type" - ] - } - ] - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "OwnerInternal": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Owner membership ID" - }, - "name": { - "type": "string", - "description": "Owner display name" - } - }, - "required": [ - "id", - "name" - ], - "description": "Content owner" - }, - "ContentShareScope": { - "type": "string", - "enum": [ - "restricted", - "organization" - ], - "description": "Content access scope" - }, - "InternalFolder": { - "type": [ - "object", - "null" - ], - "properties": { - "id": { - "type": "string", - "description": "Folder ID" - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Folder name" - }, - "path": { - "type": "string", - "description": "Folder path" - }, - "scope": { - "$ref": "#/components/schemas/ContentShareScope" - } - }, - "required": [ - "id", - "name", - "path", - "scope" - ], - "description": "Parent folder" - }, - "ApiDocument": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Content name" - }, - "owner": { - "$ref": "#/components/schemas/OwnerInternal" - }, - "scope": { - "$ref": "#/components/schemas/ContentShareScope" - }, - "_count": { - "type": "object", - "properties": { - "favorites": { - "type": "number", - "description": "Number of users who favorited" - }, - "views": { - "type": "number", - "description": "Number of views" - } - }, - "required": [ - "favorites", - "views" - ], - "description": "Document counts" - }, - "connectionId": { - "type": "string", - "description": "Connection ID" - }, - "deleted": { - "type": "boolean", - "description": "Whether document is deleted" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description" - }, - "folder": { - "$ref": "#/components/schemas/InternalFolder" - }, - "hasApp": { - "type": "boolean", - "description": "Whether document has an app" - }, - "hasDashboard": { - "type": "boolean", - "description": "Whether document has a dashboard" - }, - "identifier": { - "type": "string", - "description": "Document identifier" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Applied labels" - }, - "lastViewedAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Last time the dashboard was viewed" - }, - "updatedAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Last updated timestamp" - }, - "url": { - "type": "string", - "description": "URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an app, otherwise the workbook URL.", - "example": "https://org.omni.co/dashboards/abc123" - }, - "visits": { - "type": [ - "number", - "null" - ], - "description": "Number of dashboard visits" - } - }, - "required": [ - "name", - "owner", - "scope", - "connectionId", - "deleted", - "folder", - "hasApp", - "hasDashboard", - "identifier", - "updatedAt", - "url" - ] - }, - "DashboardsDownloadResponse": { - "type": "object", - "properties": { - "job_id": { - "type": "string", - "format": "uuid", - "description": "ID of the download job. Use this to poll for download status.", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "message": { - "type": "string", - "description": "Status message", - "example": "Download initiated successfully" - } - }, - "required": [ - "job_id", - "message" - ] - }, - "DashboardsDownloadBody": { - "type": "object", - "properties": { - "enableFormatting": { - "type": "boolean", - "default": false, - "description": "Compatible with csv, xlsx & json formats. If true, formatting will be enabled in the output. Note: If true for json format, a queryIdentifierMapKey is required.", - "example": false - }, - "expandTablesToShowAllRows": { - "type": "boolean", - "description": "Compatible with pdf and png formats. If true, up to 1,000 rows in table visualizations will be included in the delivery. Note: This parameter cannot be used when paperFormat: fit_page.", - "example": false - }, - "filterConfig": { - "description": "An object specifying the filter conditions to apply to the task. The filter key specified must already exist in the dashboard.", - "example": { - "status": [ - "active", - "pending" - ] - } - }, - "format": { - "type": "string", - "enum": [ - "pdf", - "png", - "csv", - "xlsx", - "json" - ], - "description": "Output format for the download: pdf, png, csv, xlsx, or json", - "example": "pdf" - }, - "hideHiddenFields": { - "type": "boolean", - "default": false, - "description": "Compatible with csv & xlsx formats. If true, fields marked as hidden won't be displayed in the output.", - "example": false - }, - "hideTitle": { - "type": "boolean", - "default": false, - "description": "Compatible with pdf & png formats. If true, the content's title will be hidden in the output.", - "example": false - }, - "maxRowLimit": { - "type": "number", - "minimum": 1, - "description": "Compatible with csv, json, & xlsx formats. Used with overrideRowLimit. Specifies the maximum number of rows.", - "example": 1000 - }, - "overrideRowLimit": { - "type": "boolean", - "default": false, - "description": "Compatible with csv, json, & xlsx formats. If true, the default row limit will be overridden. Note: If true for json and xlsx formats, a queryIdentifierMapKey is required.", - "example": false - }, - "paperFormat": { - "type": "string", - "enum": [ - "a3", - "a4", - "fit_page", - "legal", - "letter", - "tabloid" - ], - "description": "Compatible with pdf formats. Defines the paper format (size) of the resulting PDF. Must be one of: a3, a4, letter, legal, fit_page, tabloid.", - "example": "letter" - }, - "paperOrientation": { - "type": "string", - "enum": [ - "portrait", - "landscape" - ], - "description": "Compatible with pdf formats. Defines the paper orientation of the resulting PDF. Must be one of: portrait, landscape.", - "example": "landscape" - }, - "queryIdentifierMapKey": { - "type": "string", - "description": "Required for single tile tasks. The ID of the query to include in a single tile task. Must reference a valid query in the dashboard.", - "example": "Jmn2r3KV" - }, - "showContentLink": { - "type": "boolean", - "default": true, - "description": "Compatible with all formats except link_only. If true, a link to the content will be shown in the output.", - "example": true - }, - "showFilters": { - "type": "boolean", - "default": true, - "description": "Compatible with all formats except link_only & csv. If true, filters will be shown in the output.", - "example": true - }, - "singleColumnLayout": { - "type": "boolean", - "description": "Compatible with pdf and png formats. If true, dashboard tiles will be arranged into a single vertical column.", - "example": false - }, - "useCache": { - "type": "boolean", - "default": false, - "description": "If true, allow scheduled queries to use cached results instead of always running fresh queries.", - "example": false - }, - "filename": { - "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Custom filename for the downloaded file (without extension)", - "example": "monthly-report" - } - }, - "required": [ - "format" - ], - "additionalProperties": false - }, - "DashboardFiltersResponse": { - "type": "object", - "properties": { - "controls": { - "description": "Control configuration object. Keys are control IDs, values contain controlType, filterId, label, etc." - }, - "filterOrder": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Ordered list of filter IDs defining display order", - "example": [ - "filter_abc123", - "filter_def456" - ] - }, - "filters": { - "description": "Filter configuration object. Keys are filter IDs, values contain fieldName, viewName, kind, defaultValue, etc." - }, - "identifier": { - "type": "string", - "description": "Dashboard identifier", - "example": "12db1a0a" - } - }, - "required": [ - "filterOrder", - "identifier" - ] - }, - "DashboardsUpdateFiltersBody": { - "type": "object", - "properties": { - "clearExistingDraft": { - "type": "boolean", - "default": false, - "description": "When true, discards any existing draft before applying updates. Required when updating a published document that already has a draft." - }, - "controls": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": {}, - "additionalProperties": {} - }, - "description": "Partial control updates. Keys are control IDs that must exist in the dashboard." - }, - "filterOrder": { - "type": "array", - "items": { - "type": "string" - }, - "description": "New order for filters. All filter IDs must exist in the dashboard." - }, - "filters": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": {}, - "additionalProperties": {} - }, - "description": "Partial filter updates. Keys are filter IDs that must exist in the dashboard." - } - } - }, - "DocumentsListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Document" - }, - "description": "List of documents" - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "Document": { - "type": "object", - "properties": { - "_count": { - "type": "object", - "properties": { - "favorites": { - "type": "number", - "description": "Number of users who favorited this document" - }, - "views": { - "type": "number", - "description": "Number of views" - } - }, - "required": [ - "favorites", - "views" - ], - "description": "Document counts (included when _count is in include param)" - }, - "connectionId": { - "type": "string", - "description": "Connection ID the document is associated with" - }, - "deleted": { - "type": "boolean", - "description": "Whether the document is deleted (archived)" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description" - }, - "folder": { - "$ref": "#/components/schemas/DocumentFolder" - }, - "hasApp": { - "type": "boolean", - "description": "Whether the document has an associated app" - }, - "hasDashboard": { - "type": "boolean", - "description": "Whether the document has an associated dashboard" - }, - "identifier": { - "type": "string", - "description": "Document identifier", - "example": "abc123" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels applied to the document (included when labels is in include param)" - }, - "name": { - "type": "string", - "description": "Document name" - }, - "owner": { - "$ref": "#/components/schemas/DocumentOwner" - }, - "scope": { - "type": "string", - "enum": [ - "restricted", - "organization" - ], - "description": "Document access scope" - }, - "type": { - "type": "string", - "enum": [ - "document" - ], - "description": "Content type" - }, - "updatedAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Last updated timestamp" - }, - "url": { - "type": "string", - "description": "URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an app, otherwise the workbook URL.", - "example": "https://org.omni.co/dashboards/abc123" - } - }, - "required": [ - "connectionId", - "deleted", - "folder", - "hasDashboard", - "identifier", - "name", - "owner", - "scope", - "type", - "updatedAt", - "url" - ] - }, - "DocumentFolder": { - "type": [ - "object", - "null" - ], - "properties": { - "id": { - "type": "string", - "description": "Folder ID" - }, - "name": { - "type": "string", - "description": "Folder name" - }, - "path": { - "type": "string", - "description": "Folder path" - }, - "scope": { - "type": "string", - "enum": [ - "restricted", - "organization" - ], - "description": "Folder access scope" - } - }, - "required": [ - "id", - "name", - "path", - "scope" - ], - "description": "Folder containing the document" - }, - "DocumentOwner": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Owner membership ID" - }, - "name": { - "type": "string", - "description": "Owner display name" - } - }, - "required": [ - "id", - "name" - ], - "description": "Document owner" - }, - "DocumentsCreateResponse": { - "type": "object", - "properties": { - "dashboard": { - "type": "object", - "properties": { - "dashboardId": { - "type": "string", - "description": "Dashboard ID" - }, - "id": { - "type": "string", - "description": "Dashboard ID" - } - }, - "required": [ - "dashboardId", - "id" - ], - "additionalProperties": {}, - "description": "Created dashboard" - }, - "workbook": { - "type": "object", - "properties": { - "documentId": { - "type": "string", - "description": "Document ID (deprecated)" - }, - "id": { - "type": "string", - "description": "Workbook ID" - } - }, - "required": [ - "documentId", - "id" - ], - "additionalProperties": {}, - "description": "Created workbook" - } - }, - "required": [ - "dashboard", - "workbook" - ] - }, - "DocumentsCreateBody": { - "type": "object", - "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Optional branch ID to associate the document with a model branch", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description" - }, - "facetFilters": { - "type": "boolean", - "description": "Enable facet filters on the dashboard" - }, - "filterConfig": { - "description": "Dashboard filter configuration" - }, - "filterOrder": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Order of filters in the dashboard" - }, - "identifier": { - "$ref": "#/components/schemas/DocumentIdentifier" - }, - "metadata": { - "description": "Dashboard metadata" - }, - "metadataVersion": { - "type": "string", - "description": "Dashboard metadata version (required when metadata is provided)" - }, - "modelId": { - "type": "string", - "description": "Shared model ID to base the document on" - }, - "name": { - "type": "string", - "description": "Document name" - }, - "queryPresentations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "aiConfig": { - "description": "AI configuration" - }, - "chartType": { - "type": [ - "string", - "null" - ], - "description": "Chart type" - }, - "description": { - "type": "string", - "maxLength": 500, - "description": "Query presentation description" - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 144, - "description": "Query presentation name" - }, - "prefersChart": { - "type": "boolean", - "description": "Whether to prefer chart view" - }, - "query": { - "type": "object", - "properties": { - "fields": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Query fields" - }, - "table": { - "type": "string", - "description": "Query table/topic" - } - }, - "required": [ - "fields", - "table" - ], - "additionalProperties": {}, - "description": "Query definition" - }, - "resultConfig": { - "description": "Result configuration" - }, - "subTitle": { - "type": "string", - "maxLength": 250, - "description": "Subtitle" - }, - "topicName": { - "type": [ - "string", - "null" - ], - "maxLength": 256, - "description": "Topic name. Omit or pass null for raw-SQL tiles or any tile with no semantic topic." - }, - "visConfig": { - "$ref": "#/components/schemas/ApiVisConfig" - } - }, - "required": [ - "name", - "query" - ] - }, - "description": "Query presentations for the document" - } - }, - "required": [ - "modelId", - "name" - ] - }, - "DocumentIdentifier": { - "type": "string", - "minLength": 2, - "maxLength": 48, - "description": "Optional document identifier. If omitted, an identifier is auto-generated. Must be unique within the organization." - }, - "ApiVisConfig": { - "type": "object", - "additionalProperties": true, - "description": "Visualization configuration (Not statically modeled; use plain dicts.)" - }, - "DocumentsGetResponse": { - "type": "object", - "properties": { - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description" - }, - "documentMetadata": { - "description": "Document metadata" - }, - "facetFilters": { - "type": "boolean", - "description": "Whether facet filters are enabled" - }, - "filterConfig": { - "description": "Dashboard filter configuration" - }, - "filterOrder": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Order of filters" - }, - "modelId": { - "type": "string", - "description": "Model ID" - }, - "name": { - "type": "string", - "description": "Document name" - }, - "queryPresentations": { - "type": "array", - "items": {}, - "description": "Query presentations" - }, - "refreshInterval": { - "type": [ - "number", - "null" - ], - "description": "Auto-refresh interval in seconds" - } - }, - "required": [ - "facetFilters", - "filterOrder", - "modelId", - "name", - "queryPresentations", - "refreshInterval" - ] - }, - "DocumentsPutResponse": { - "type": "object", - "properties": { - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description" - }, - "identifier": { - "type": "string", - "description": "Document identifier" - }, - "name": { - "type": "string", - "description": "Updated document name" - } - }, - "required": [ - "identifier", - "name" - ] - }, - "DocumentsPutBody": { - "type": "object", - "properties": { - "clearExistingDraft": { - "type": "boolean", - "default": false, - "description": "Clear existing draft before updating (for published documents with drafts)" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description" - }, - "documentMetadata": { - "description": "Document presentation metadata" - }, - "facetFilters": { - "type": "boolean", - "description": "Enable facet filters" - }, - "filterConfig": { - "description": "Filter configuration" - }, - "filterOrder": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Order of filters" - }, - "modelId": { - "type": "string", - "description": "Model ID" - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 254, - "description": "Document name" - }, - "queryPresentations": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DocumentsPutQueryPresentation" - }, - "minItems": 1, - "description": "Query presentations (full replacement)" - }, - "refreshInterval": { - "type": [ - "integer", - "null" - ], - "minimum": 60, - "description": "Auto-refresh interval in seconds" - } - }, - "required": [ - "facetFilters", - "filterOrder", - "modelId", - "name", - "queryPresentations", - "refreshInterval" - ] - }, - "DocumentsPutQueryPresentation": { - "type": "object", - "properties": { - "aiConfig": { - "type": "object", - "properties": { - "description": { - "type": "object", - "properties": { - "aiContext": { - "type": "string" - }, - "enabled": { - "type": "boolean" - } - } - }, - "subTitle": { - "type": "object", - "properties": { - "aiContext": { - "type": "string" - }, - "enabled": { - "type": "boolean" - } - } - } - }, - "description": "AI configuration" - }, - "chartType": { - "type": [ - "string", - "null" - ], - "enum": [ - "auto", - "area", - "areaStacked", - "areaStackedPercentage", - "bar", - "barLine", - "barGrouped", - "barStacked", - "barStackedPercentage", - "boxplot", - "code", - "column", - "columnGrouped", - "columnStacked", - "columnStackedPercentage", - "heatmap", - "kpi", - "line", - "lineColor", - "map", - "regionMap", - "markdown", - "omni-ai-summary-markdown", - "pie", - "funnel", - "sankey", - "point", - "pointColor", - "pointSize", - "pointSizeColor", - "singleRecord", - "omni-spreadsheet", - "summaryValue", - "svgMap", - "table", - "treemap", - null - ], - "description": "Chart type" - }, - "description": { - "type": "string", - "maxLength": 500, - "description": "Description" - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 144, - "description": "Query presentation name" - }, - "prefersChart": { - "type": "boolean", - "description": "Whether to prefer chart view" - }, - "query": { - "description": "Query definition" - }, - "queryIdentifierMapKey": { - "type": "string", - "pattern": "^[1-9][0-9]*$", - "description": "Round-trip preservation hint. When the value matches an existing key on the document, the tile keeps its map key (and dashboard containers stay attached). Omit for new tiles. Must be a positive integer string (e.g. \"1\", \"2\", \"10\")." - }, - "resultConfig": { - "description": "Result config" - }, - "subTitle": { - "type": "string", - "maxLength": 250, - "description": "Subtitle" - }, - "topicName": { - "type": [ - "string", - "null" - ], - "maxLength": 256, - "description": "Topic name. Omit or pass null for raw-SQL tiles or any tile with no semantic topic." - }, - "visConfig": { - "$ref": "#/components/schemas/ApiVisConfig" - } - }, - "required": [ - "name" - ] - }, - "DocumentsUpdateResponse": { - "type": "object", - "properties": { - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description" - }, - "identifier": { - "type": "string", - "description": "Document identifier" - }, - "name": { - "type": "string", - "description": "Updated document name" - } - }, - "required": [ - "identifier", - "name" - ] - }, - "DocumentsUpdateBody": { - "type": "object", - "properties": { - "clearExistingDraft": { - "type": "boolean", - "default": false, - "description": "Clear existing draft before updating (for published documents with drafts)" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description" - }, - "identifier": { - "$ref": "#/components/schemas/DocumentIdentifier" - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 254, - "description": "New document name" - } - } - }, - "SuccessResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation was successful", - "example": true - } - }, - "required": [ - "success" - ] - }, - "DocumentsGetQueriesResponse": { - "type": "object", - "properties": { - "queries": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Query presentation ID" - }, - "name": { - "type": "string", - "description": "Query presentation name" - }, - "query": { - "description": "Query JSON definition" - }, - "queryIdentifierMapKey": { - "type": "string", - "description": "Key in the query identifier map" - }, - "url": { - "type": "string", - "description": "URL to view this specific query/sheet in the workbook.", - "example": "https://org.omni.co/w/abc123?key=1" - } - }, - "required": [ - "id", - "name", - "queryIdentifierMapKey", - "url" - ] - }, - "description": "List of queries in the document" - } - }, - "required": [ - "queries" - ] - }, - "DocumentsMoveBody": { - "type": "object", - "properties": { - "folderPath": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "description": "Destination folder path (null for root)" - }, - "scope": { - "type": "string", - "enum": [ - "restricted", - "organization" - ], - "description": "Access scope for the document" - } - }, - "required": [ - "folderPath" - ] - }, - "DocumentsGetPermissionsResponse": { - "type": "object", - "properties": { - "permits": { - "description": "User permits for the document" - } - } - }, - "DocumentsUpdatePermissionSettingsBody": { - "type": "object", - "properties": { - "canDownload": { - "type": "boolean", - "description": "Allow downloading" - }, - "canDrill": { - "type": "boolean", - "description": "Allow drill-down" - }, - "canSchedule": { - "type": "boolean", - "description": "Allow scheduling" - }, - "canUpload": { - "type": "boolean", - "description": "Allow uploads" - }, - "canUseDashboardAi": { - "type": "boolean", - "description": "Allow using dashboard AI" - }, - "canUseTimezoneOverride": { - "type": "boolean", - "description": "Allow timezone override" - }, - "canViewWorkbook": { - "type": "boolean", - "description": "Allow viewing workbook" - }, - "organizationAccessBoost": { - "type": "boolean", - "description": "Boost organization access" - }, - "organizationRole": { - "type": "string", - "enum": [ - "viewer", - "editor", - "manager", - "no_access" - ], - "description": "Organization-wide role for the document" - }, - "requirePullRequestToPublish": { - "type": "boolean", - "description": "Require pull request to publish changes" - } - } - }, - "DocumentsAddPermitsBody": { - "type": "object", - "properties": { - "accessBoost": { - "type": "boolean", - "default": false, - "description": "Grant access boost" - }, - "role": { - "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "EXPLORER", - "EDITOR", - "MANAGER" - ], - "description": "Role to grant" - }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to grant access to" - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User membership IDs to grant access to" - } - }, - "required": [ - "role" - ] - }, - "DocumentsUpdatePermitsBody": { - "type": "object", - "properties": { - "accessBoost": { - "type": "boolean", - "description": "Access boost setting" - }, - "role": { - "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "EXPLORER", - "EDITOR", - "MANAGER" - ], - "description": "Role to set" - }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to update" - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User membership IDs to update" - } - } - }, - "DocumentsRevokePermitsBody": { - "type": "object", - "properties": { - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to revoke access from" - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User membership IDs to revoke access from" - } - } - }, - "DocumentsCreateDraftResponse": { - "type": "object", - "properties": { - "identifier": { - "type": "string", - "description": "Draft document identifier" - } - }, - "required": [ - "identifier" - ] - }, - "DocumentsCreateDraftBody": { - "type": "object", - "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Branch ID for the draft" - } - } - }, - "DocumentsDiscardDraftResponse": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Success message" - } - }, - "required": [ - "message" - ] - }, - "DocumentsDiscardDraftBody": { - "type": "object", - "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Branch ID for the draft" - } - } - }, - "DocumentsListDraftsResponse": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApiDraft" - } - }, - "ApiDraft": { - "type": "object", - "properties": { - "branch": { - "$ref": "#/components/schemas/ApiDraftBranch" - }, - "createdAt": { - "type": "string", - "format": "date-time", - "description": "When the draft was created" - }, - "createdBy": { - "$ref": "#/components/schemas/ApiDraftActor" - }, - "draftOutOfDate": { - "type": "boolean", - "description": "True when the published document was published more recently than the draft was created (the draft is based on a stale baseline)" - }, - "identifier": { - "type": "string", - "description": "Draft workbook identifier \u2014 use this to address the draft" - }, - "lastEditedBy": { - "$ref": "#/components/schemas/ApiDraftActor" - }, - "publishedIdentifier": { - "type": "string", - "description": "Identifier of the published document the draft is for" - }, - "status": { - "$ref": "#/components/schemas/ApiDraftStatus" - }, - "updatedAt": { - "type": "string", - "format": "date-time", - "description": "Most recent edit time on the draft workbook" - }, - "workbookModelId": { - "type": "string", - "format": "uuid", - "description": "omni_model ID for the draft workbook" - } - }, - "required": [ - "branch", - "createdAt", - "createdBy", - "draftOutOfDate", - "identifier", - "lastEditedBy", - "publishedIdentifier", - "status", - "updatedAt", - "workbookModelId" - ] - }, - "ApiDraftBranch": { - "type": [ - "object", - "null" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Branch (omni model) ID" - }, - "name": { - "type": "string", - "description": "Branch name" - } - }, - "required": [ - "id", - "name" - ], - "description": "Branch the draft is attached to, or null for a draft on main" - }, - "ApiDraftActor": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Display name" - } - }, - "required": [ - "name" - ], - "description": "User who created the draft" - }, - "ApiDraftStatus": { - "type": "string", - "enum": [ - "active", - "archived" - ], - "description": "Lifecycle status: \"active\" for current drafts, \"archived\" for soft-deleted drafts (retained ~7 days)" - }, - "DocumentsDuplicateResponse": { - "type": "object", - "properties": { - "dashboardId": { - "type": "string", - "description": "New dashboard ID" - }, - "identifier": { - "type": "string", - "description": "New document identifier" - }, - "name": { - "type": "string", - "description": "Document name" - }, - "workbookId": { - "type": "string", - "description": "New workbook ID" - } - }, - "required": [ - "dashboardId", - "identifier", - "name", - "workbookId" - ] - }, - "DocumentsDuplicateBody": { - "type": "object", - "properties": { - "folderPath": { - "type": [ - "string", - "null" - ], - "description": "Destination folder path (null for root)" - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 254, - "description": "Name for the duplicated document" - }, - "scope": { - "type": "string", - "enum": [ - "restricted", - "organization" - ], - "description": "Access scope for the duplicated document" - } - }, - "required": [ - "name" - ] - }, - "DocumentsUpgradeLayoutResponse": { - "type": "object", - "properties": { - "identifier": { - "type": "string", - "description": "Document identifier" - }, - "upgraded": { - "type": "boolean", - "description": "True when the layout was upgraded, false when the document already had advanced layout (no-op)." - } - }, - "required": [ - "identifier", - "upgraded" - ] - }, - "DocumentsUpgradeLayoutBody": { - "type": "object", - "properties": { - "clearExistingDraft": { - "type": "boolean", - "default": false, - "description": "When upgrading a published document, discard any existing draft instead of failing with a conflict." - } - } - }, - "DocumentsBulkUpdateLabelsResponse": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Updated list of labels on the document" - } - }, - "required": [ - "labels" - ] - }, - "DocumentsBulkUpdateLabelsBody": { - "type": "object", - "properties": { - "add": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "Labels to add" - }, - "remove": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "Labels to remove" - } - } - }, - "DocumentsTransferOwnershipBody": { - "type": "object", - "properties": { - "userId": { - "type": "string", - "format": "uuid", - "description": "Membership ID of the new owner" - } - }, - "required": [ - "userId" - ] - }, - "DocumentsAccessListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "principals": { - "type": "array", - "items": {}, - "description": "List of users and groups with access" - } - }, - "required": [ - "pageInfo", - "principals" - ] - }, - "DocumentsListFavoritesResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DocumentFavoriteUser" - }, - "description": "Users who favorited this document" - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "DocumentFavoriteUser": { - "type": "object", - "properties": { - "email": { - "type": [ - "string", - "null" - ], - "description": "Favoriting user's email. Null when the user has no resolvable email \u2014 e.g. an embed-SSO favoriter whose embed session did not provide one." - }, - "favoritedAt": { - "type": "string", - "description": "ISO 8601 timestamp when the user favorited the document" - }, - "name": { - "type": "string", - "description": "Favoriting user's display name" - }, - "userId": { - "type": "string", - "description": "Membership ID of the user who favorited the document (use with other v1 endpoints' userId parameter)" - } - }, - "required": [ - "email", - "favoritedAt", - "name", - "userId" - ] - }, - "DocumentsV2CreateResponse": { - "type": "object", - "properties": { - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description." - }, - "identifier": { - "type": "string", - "description": "Identifier of the newly created document." - }, - "name": { - "type": "string", - "description": "Document name." - } - }, - "required": [ - "description", - "identifier", - "name" - ] - }, - "DocumentsV2CreateBody": { - "type": "object", - "properties": { - "containers": { - "$ref": "#/components/schemas/ContainersOnCreate" - }, - "controls": { - "$ref": "#/components/schemas/ControlsPatchExternal" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description." - }, - "folderId": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Folder to create the document in. When omitted, defaults to the caller\u2019s personal \"My documents\" (requires permission to save personal content \u2014 otherwise the request is rejected)." - }, - "identifier": { - "$ref": "#/components/schemas/DocumentIdentifier" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Base workbook model the document is built on \u2014 a SHARED model, or a SHARED_EXTENSION with `allowAsWorkbookBase = true`." - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 254, - "description": "Document name." - }, - "queryPresentations": { - "$ref": "#/components/schemas/QueryPresentationsPatchExternal" - }, - "settings": { - "$ref": "#/components/schemas/SettingsPatchExternal" - }, - "summary": { - "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Optional. Caller-supplied note describing the create, written to the history audit trail. When omitted, the server auto-fills it with \"Created document\"." - } - }, - "required": [ - "modelId", - "name" - ], - "additionalProperties": false - }, - "ContainersOnCreate": { - "type": [ - "array", - "null" - ], - "items": { - "anyOf": [ - { - "$ref": "#/components/schemas/GridContainer" - }, - { - "$ref": "#/components/schemas/PageContainer" - }, - { - "$ref": "#/components/schemas/StackContainer" - } - ] - }, - "description": "Container layout array, or `null` to create a workbook-only document with no dashboard. When `null`, `controls` and `settings` must be omitted." - }, - "GridContainer": { - "type": "object", - "additionalProperties": true, - "description": "Grid container \u2014 children are positioned on a grid (each carries a gridPosition). (Not statically modeled; use plain dicts.)" - }, - "StackContainer": { - "type": "object", - "additionalProperties": true, - "description": "Stack container \u2014 an ordered list of nested children (content, grid, stack, or reference). (Not statically modeled; use plain dicts.)" - }, - "ReferenceContainer": { - "type": "object", - "additionalProperties": true, - "description": "Reference container \u2014 points at another container in the collection by its instanceKey. (Not statically modeled; use plain dicts.)" - }, - "PageContainer": { - "type": "object", - "additionalProperties": true, - "description": "Page container \u2014 a top-level page wrapping a single grid, stack, or reference container, optionally per breakpoint/media. (Not statically modeled; use plain dicts.)" - }, - "ControlsPatchExternal": { - "type": "object", - "additionalProperties": true, - "description": "(Not statically modeled; use plain dicts.)" - }, - "ControlPatchExternal": { - "type": "object", - "additionalProperties": true, - "description": "(Not statically modeled; use plain dicts.)" - }, - "JsonValue": { - "type": "object", - "additionalProperties": true, - "description": "Arbitrary JSON value (string, number, boolean, null, object, or array). (Not statically modeled; use plain dicts.)" - }, - "QueryPresentationsPatchExternal": { - "type": "object", - "additionalProperties": true, - "description": "(Not statically modeled; use plain dicts.)" - }, - "QueryPresentationPatchExternal": { - "type": "object", - "additionalProperties": true, - "description": "(Not statically modeled; use plain dicts.)" - }, - "SettingsPatchExternal": { - "type": "object", - "properties": { - "crossfilterEnabled": { - "type": "boolean", - "description": "When true, clicking a value in one tile filters all other tiles on the dashboard." - }, - "customText": { - "type": [ - "object", - "null" - ], - "properties": { - "queryError": { - "type": "string", - "description": "Custom text shown when a query errors, replacing the default error text." - }, - "queryNoResults": { - "type": "string", - "description": "Custom text shown when a query returns no results, replacing the default empty state." - } - }, - "description": "Custom text replacing default UI strings on the dashboard, e.g. when queries error or return no results." - }, - "facetFilters": { - "type": "boolean", - "description": "When true, dashboard filters are applied per-facet when faceting is active." - }, - "refreshInterval": { - "type": [ - "number", - "null" - ], - "description": "Auto-refresh interval in seconds. Null disables auto-refresh." - }, - "runQueriesOn": { - "type": [ - "string", - "null" - ], - "enum": [ - "current-page", - "all-pages", - null - ], - "description": "Controls whether dashboard queries execute on the visible page or across all pages." - } - }, - "description": "Document settings. Shallow-merged with the existing settings." - }, - "DocumentsV2ReadResponse": { - "type": "object", - "properties": { - "containers": { - "$ref": "#/components/schemas/Containers" - }, - "controls": { - "$ref": "#/components/schemas/ControlsReadExternal" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description." - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Base model the document is built on (the `modelId` supplied at create). Immutable \u2014 echoed here so a GET round-trips through PATCH; supplying a different value on PATCH is rejected." - }, - "name": { - "type": "string", - "maxLength": 254, - "description": "Document name." - }, - "queryPresentations": { - "$ref": "#/components/schemas/QueryPresentationsReadExternal" - }, - "settings": { - "$ref": "#/components/schemas/SettingsReadExternal" - } - }, - "required": [ - "description", - "modelId", - "name", - "queryPresentations" - ] - }, - "Containers": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": true - }, - "description": "Container layout array (grid / stack / page / reference containers, recursively nested). The server validates the full structure on apply. (Not statically modeled; use plain dicts.)" - }, - "ControlsReadExternal": { - "type": "object", - "additionalProperties": true, - "description": "(Not statically modeled; use plain dicts.)" - }, - "ControlReadExternal": { - "type": "object", - "additionalProperties": true, - "description": "(Not statically modeled; use plain dicts.)" - }, - "QueryPresentationsReadExternal": { - "type": "object", - "additionalProperties": true, - "description": "(Not statically modeled; use plain dicts.)" - }, - "QueryPresentationReadExternal": { - "type": "object", - "additionalProperties": true, - "description": "(Not statically modeled; use plain dicts.)" - }, - "SettingsReadExternal": { - "type": "object", - "properties": { - "crossfilterEnabled": { - "type": "boolean", - "description": "When true, clicking a value in one tile filters all other tiles on the dashboard." - }, - "customText": { - "type": [ - "object", - "null" - ], - "properties": { - "queryError": { - "type": "string", - "description": "Custom text shown when a query errors, replacing the default error text." - }, - "queryNoResults": { - "type": "string", - "description": "Custom text shown when a query returns no results, replacing the default empty state." - } - }, - "description": "Custom text replacing default UI strings on the dashboard, e.g. when queries error or return no results." - }, - "facetFilters": { - "type": "boolean", - "description": "When true, dashboard filters are applied per-facet when faceting is active." - }, - "refreshInterval": { - "type": [ - "number", - "null" - ], - "description": "Auto-refresh interval in seconds. Null disables auto-refresh." - }, - "runQueriesOn": { - "type": [ - "string", - "null" - ], - "enum": [ - "current-page", - "all-pages", - null - ], - "description": "Controls whether dashboard queries execute on the visible page or across all pages." - } - }, - "required": [ - "crossfilterEnabled", - "customText", - "facetFilters", - "refreshInterval", - "runQueriesOn" - ] - }, - "DocumentsV2PatchDraftResponse": { - "type": "object", - "properties": { - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description." - }, - "draftIdentifier": { - "type": "string", - "description": "Identifier of the draft the patch was applied to." - }, - "identifier": { - "type": "string", - "description": "Published document identifier the draft targets." - }, - "name": { - "type": "string", - "description": "Document name." - } - }, - "required": [ - "description", - "draftIdentifier", - "identifier", - "name" - ] - }, - "DocumentsV2CreateDraftBody": { - "allOf": [ - { - "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" - }, - { - "type": "object", - "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Branch the draft is created on. Omit for a draft on the main (unpublished) workspace." - } - }, - "additionalProperties": false - } - ] - }, - "DocumentsV2PatchDraftBody": { - "type": "object", - "properties": { - "containers": { - "$ref": "#/components/schemas/Containers" - }, - "controls": { - "$ref": "#/components/schemas/ControlsPatchExternal" - }, - "description": { - "type": [ - "string", - "null" - ] - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 254, - "description": "Document name." - }, - "queryPresentations": { - "$ref": "#/components/schemas/QueryPresentationsPatchExternal" - }, - "settings": { - "$ref": "#/components/schemas/SettingsPatchExternal" - }, - "summary": { - "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Optional. Caller-supplied description of what this patch changes, written to the history audit trail. When omitted, the server auto-generates one from the touched sections." - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The document's base model. Immutable and accepted only so a GET response round-trips through PATCH: a value matching the current model is a no-op, and a differing value is rejected \u2014 it cannot re-base the document. Omit it to leave the model untouched." - } - }, - "additionalProperties": false - }, - "DocumentsV2PublishDraftResponse": { - "type": "object", - "properties": { - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description." - }, - "identifier": { - "type": "string", - "description": "Published document identifier." - }, - "name": { - "type": "string", - "description": "Document name." - } - }, - "required": [ - "description", - "identifier", - "name" - ] - }, - "DocumentsV2UpdateIdentifierResponse": { - "type": "object", - "properties": { - "description": { - "type": [ - "string", - "null" - ], - "description": "Document description." - }, - "identifier": { - "type": "string", - "description": "The document identifier after the rename." - }, - "name": { - "type": "string", - "description": "Document name." - } - }, - "required": [ - "description", - "identifier", - "name" - ] - }, - "DocumentsV2UpdateIdentifierBody": { - "type": "object", - "properties": { - "identifier": { - "$ref": "#/components/schemas/DocumentIdentifier" - } - }, - "required": [ - "identifier" - ], - "additionalProperties": false - }, - "EmbedSsoGenerateSessionResponse": { - "type": "object", - "properties": { - "sessionId": { - "type": "string", - "description": "Session ID to use for embedding Omni content" - } - }, - "required": [ - "sessionId" - ] - }, - "EmbedSsoGenerateSessionBody": { - "type": "object", - "properties": { - "externalId": { - "type": "string", - "description": "External identifier for the user (from your system)", - "example": "user-123" - }, - "groups": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Optional list of non-entity group names to assign to the user. Entity-group membership is managed by the entity parameter.", - "example": [ - "engineering", - "sales" - ] - }, - "name": { - "type": "string", - "description": "Display name for the user", - "example": "John Doe" - }, - "userAttributes": { - "type": "object", - "additionalProperties": {}, - "description": "Optional user attributes for row-level security" - } - }, - "required": [ - "externalId", - "name" - ] - }, - "EvalPromptSetsListResponse": { - "type": "object", - "properties": { - "prompt_sets": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EvalPromptSetListItem" - }, - "description": "Prompt sets matching the query, sorted alphabetically by name." - } - }, - "required": [ - "prompt_sets" - ] - }, - "EvalPromptSetListItem": { - "type": "object", - "properties": { - "created_at": { - "type": [ - "string", - "null" - ], - "description": "ISO 8601 timestamp when the prompt set was created.", - "example": "2025-01-15T10:00:00.000Z" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Optional human-readable description of the prompt set.", - "example": "Regression suite for the orders topic" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "is_archived": { - "type": "boolean", - "description": "Whether the prompt set has been archived.", - "example": false - }, - "model_id": { - "type": "string", - "format": "uuid", - "description": "The shared model this prompt set is bound to.", - "example": "880e8400-e29b-41d4-a716-446655440003" - }, - "name": { - "type": "string", - "description": "Human-readable name for the prompt set.", - "example": "Orders regression" - }, - "slug": { - "type": "string", - "description": "URL-safe identifier for the prompt set. Unique per `model_id`.", - "example": "orders-regression" - }, - "updated_at": { - "type": [ - "string", - "null" - ], - "description": "ISO 8601 timestamp when the prompt set was last updated.", - "example": "2025-01-15T10:00:00.000Z" - }, - "latest_run_at": { - "type": [ - "string", - "null" - ], - "description": "ISO 8601 timestamp of the most recent run on this prompt set, if any.", - "example": "2025-01-15T10:05:00.000Z" - }, - "prompt_count": { - "type": "integer", - "description": "Number of prompts in the set.", - "example": 12 - } - }, - "required": [ - "created_at", - "description", - "id", - "is_archived", - "model_id", - "name", - "slug", - "updated_at", - "latest_run_at", - "prompt_count" - ] - }, - "EvalApiError400": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Bad Request: name: Required" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 400 - } - }, - "required": [ - "detail", - "status" - ] - }, - "EvalApiError401": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Unauthorized: Missing or invalid API key" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 401 - } - }, - "required": [ - "detail", - "status" - ] - }, - "EvalApiError403": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "AI eval requires at least Querier access on the model" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 403 - } - }, - "required": [ - "detail", - "status" - ] - }, - "EvalApiError404": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Prompt set not found" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 404 - } - }, - "required": [ - "detail", - "status" - ] - }, - "EvalPromptSetsCreateResponse": { - "type": "object", - "properties": { - "prompt_set": { - "$ref": "#/components/schemas/EvalPromptSet" - } - }, - "required": [ - "prompt_set" - ] - }, - "EvalPromptSet": { - "type": "object", - "properties": { - "created_at": { - "type": [ - "string", - "null" - ], - "description": "ISO 8601 timestamp when the prompt set was created.", - "example": "2025-01-15T10:00:00.000Z" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Optional human-readable description of the prompt set.", - "example": "Regression suite for the orders topic" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "is_archived": { - "type": "boolean", - "description": "Whether the prompt set has been archived.", - "example": false - }, - "model_id": { - "type": "string", - "format": "uuid", - "description": "The shared model this prompt set is bound to.", - "example": "880e8400-e29b-41d4-a716-446655440003" - }, - "name": { - "type": "string", - "description": "Human-readable name for the prompt set.", - "example": "Orders regression" - }, - "prompts": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EvalPrompt" - }, - "description": "Prompts that make up the set." - }, - "slug": { - "type": "string", - "description": "URL-safe identifier for the prompt set. Unique per `model_id`.", - "example": "orders-regression" - }, - "updated_at": { - "type": [ - "string", - "null" - ], - "description": "ISO 8601 timestamp when the prompt set was last updated.", - "example": "2025-01-15T10:00:00.000Z" - } - }, - "required": [ - "created_at", - "description", - "id", - "is_archived", - "model_id", - "name", - "prompts", - "slug", - "updated_at" - ] - }, - "EvalPrompt": { - "type": "object", - "properties": { - "created_at": { - "type": [ - "string", - "null" - ], - "description": "ISO 8601 timestamp when the prompt was created.", - "example": "2025-01-15T10:00:00.000Z" - }, - "expectation": { - "type": [ - "string", - "null" - ], - "description": "The expectation the analysis judge scores the analysis against, or null when none was set.", - "example": "The top product by revenue should be Aniseed Syrup." - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the prompt.", - "example": "770e8400-e29b-41d4-a716-446655440002" - }, - "prompt_text": { - "type": "string", - "description": "The natural language prompt text the AI is evaluated on.", - "example": "What are the top 5 products by revenue?" - }, - "updated_at": { - "type": [ - "string", - "null" - ], - "description": "ISO 8601 timestamp when the prompt was last updated.", - "example": "2025-01-15T10:00:00.000Z" - } - }, - "required": [ - "created_at", - "expectation", - "id", - "prompt_text", - "updated_at" - ] - }, - "EvalApiError422": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "A prompt being updated does not belong to this prompt set" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 422 - } - }, - "required": [ - "detail", - "status" - ] - }, - "EvalPromptSetsCreateBody": { - "type": "object", - "properties": { - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 1024, - "description": "Optional human-readable description of the prompt set. Max 1024 characters.", - "example": "Regression suite for the orders topic" - }, - "model_id": { - "type": "string", - "format": "uuid", - "description": "The shared model this prompt set is bound to.", - "example": "880e8400-e29b-41d4-a716-446655440003" - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Human-readable name for the prompt set. 255 characters or fewer.", - "example": "Orders regression" - }, - "prompts": { - "type": "array", - "items": { - "type": "object", - "properties": { - "expectation": { - "type": [ - "string", - "null" - ], - "maxLength": 16000, - "description": "Optional expectation the analysis judge scores the analysis against. Max 16000 characters.", - "example": "The top product by revenue should be Aniseed Syrup." - }, - "prompt_text": { - "type": "string", - "minLength": 1, - "maxLength": 8000, - "description": "The natural language prompt text. Max 8000 characters.", - "example": "What are the top 5 products by revenue?" - } - }, - "required": [ - "prompt_text" - ] - }, - "maxItems": 100, - "default": [], - "description": "Initial prompts for the set. Defaults to an empty list. At most 25 prompts." - }, - "slug": { - "type": "string", - "maxLength": 255, - "pattern": "^[a-z][a-z0-9-]*$", - "description": "URL-safe identifier for the prompt set. Must be unique per `model_id` and match `^[a-z][a-z0-9-]*$`. Max 255 characters.", - "example": "orders-regression" - } - }, - "required": [ - "model_id", - "name", - "slug" - ] - }, - "EvalPromptSetsGetResponse": { - "type": "object", - "properties": { - "prompt_set": { - "$ref": "#/components/schemas/EvalPromptSet" - } - }, - "required": [ - "prompt_set" - ] - }, - "EvalPromptSetsUpdateResponse": { - "type": "object", - "properties": { - "prompt_set": { - "$ref": "#/components/schemas/EvalPromptSet" - } - }, - "required": [ - "prompt_set" - ] - }, - "EvalPromptSetsUpdateBody": { - "type": "object", - "properties": { - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 1024, - "description": "New description for the prompt set. Pass `null` to clear. Max 1024 characters." - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "New human-readable name for the prompt set. 255 characters or fewer." - }, - "prompts": { - "type": "array", - "items": { - "type": "object", - "properties": { - "expectation": { - "type": [ - "string", - "null" - ], - "maxLength": 16000, - "description": "Optional expectation the analysis judge scores the analysis against. Pass `null` to clear. Max 16000 characters.", - "example": "The top product by revenue should be Aniseed Syrup." - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Existing prompt id. When provided, updates that prompt; when omitted, a new prompt is created. Prompts not included in this list are removed." - }, - "prompt_text": { - "type": "string", - "minLength": 1, - "maxLength": 8000, - "description": "Updated or new prompt text. Max 8000 characters.", - "example": "What are the top 10 products by revenue this quarter?" - } - }, - "required": [ - "prompt_text" - ] - }, - "maxItems": 100, - "description": "Full desired set of prompts after the update. Prompts omitted from this list are deleted; new prompts (no `id`) are appended in body order. Existing prompts retain their original position \u2014 reordering is not supported on this endpoint. At most 25 prompts total." - } - } - }, - "EvalPromptSetsDeleteResponse": { - "type": "object", - "properties": { - "cancelled_job_count": { - "type": "integer", - "description": "Number of in-flight agentic jobs associated with this prompt set that were cancelled as part of the archive.", - "example": 0 - }, - "is_archived": { - "type": "boolean", - "enum": [ - true - ], - "description": "Always `true` on success \u2014 archives the prompt set." - } - }, - "required": [ - "cancelled_job_count", - "is_archived" - ] - }, - "EvalApiError500": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Archive committed but a run-cancellation failed; retry to complete" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 500 - } - }, - "required": [ - "detail", - "status" - ] - }, - "EvalPromptSetsUnarchiveResponse": { - "type": "object", - "properties": { - "prompt_set": { - "$ref": "#/components/schemas/EvalPromptSet" - } - }, - "required": [ - "prompt_set" - ] - }, - "EvalRunsListResponse": { - "type": "object", - "properties": { - "runs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EvalRunListItem" - }, - "description": "Runs for the prompt set, newest first, filtered to those whose model the caller can access." - } - }, - "required": [ - "runs" - ] - }, - "EvalRunListItem": { - "type": "object", - "properties": { - "branch_id": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Optional branch ID the run was executed against. Null when run against the main shared model.", - "example": null - }, - "branch_name": { - "type": [ - "string", - "null" - ], - "description": "Display name for the branch, if `branch_id` is set.", - "example": null - }, - "completed_at": { - "type": [ - "string", - "null" - ], - "description": "ISO 8601 timestamp when the run reached a terminal state.", - "example": null - }, - "created_at": { - "type": [ - "string", - "null" - ], - "description": "ISO 8601 timestamp when the run was created.", - "example": "2025-01-15T10:00:00.000Z" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Optional human-readable description for the run.", - "example": null - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the run.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "is_archived": { - "type": "boolean", - "description": "Whether the run has been archived.", - "example": false - }, - "model_id": { - "type": "string", - "format": "uuid", - "description": "The shared model this run was executed against.", - "example": "880e8400-e29b-41d4-a716-446655440003" - }, - "prompt_set_id": { - "type": "string", - "format": "uuid", - "description": "The prompt set this run was created from.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "run_number": { - "type": "integer", - "description": "Sequential, per-prompt-set run number.", - "example": 3 - }, - "stats": { - "$ref": "#/components/schemas/EvalRunStats" - }, - "status": { - "type": "string", - "enum": [ - "RUNNING", - "COMPLETE", - "CANCELLED" - ], - "description": "Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly once.", - "example": "RUNNING" - } - }, - "required": [ - "branch_id", - "branch_name", - "completed_at", - "created_at", - "description", - "id", - "is_archived", - "model_id", - "prompt_set_id", - "run_number", - "stats", - "status" - ] - }, - "EvalRunStats": { - "type": "object", - "properties": { - "terminal": { - "type": "integer", - "description": "Number of per-prompt jobs that have reached a terminal state (COMPLETE, FAILED, or CANCELLED).", - "example": 8 - }, - "total": { - "type": "integer", - "description": "Total number of per-prompt jobs in the run.", - "example": 12 - } - }, - "required": [ - "terminal", - "total" - ] - }, - "EvalRunsCreateResponse": { - "type": "object", - "properties": { - "job_count": { - "type": "integer", - "description": "Number of per-prompt agentic jobs created for this run (one per prompt that fanned out successfully). Enqueue onto the work queue happens after creation and is best-effort, so this count reflects jobs created, not necessarily those successfully enqueued.", - "example": 12 - }, - "run": { - "$ref": "#/components/schemas/EvalRunDetail" - } - }, - "required": [ - "job_count", - "run" - ] - }, - "EvalRunDetail": { - "type": "object", - "properties": { - "branch_id": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Optional branch ID the run was executed against. Null when run against the main shared model.", - "example": null - }, - "branch_name": { - "type": [ - "string", - "null" - ], - "description": "Display name for the branch, if `branch_id` is set.", - "example": null - }, - "completed_at": { - "type": [ - "string", - "null" - ], - "description": "ISO 8601 timestamp when the run reached a terminal state.", - "example": null - }, - "created_at": { - "type": [ - "string", - "null" - ], - "description": "ISO 8601 timestamp when the run was created.", - "example": "2025-01-15T10:00:00.000Z" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Optional human-readable description for the run.", - "example": null - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the run.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "is_archived": { - "type": "boolean", - "description": "Whether the run has been archived.", - "example": false - }, - "model_id": { - "type": "string", - "format": "uuid", - "description": "The shared model this run was executed against.", - "example": "880e8400-e29b-41d4-a716-446655440003" - }, - "prompt_set_id": { - "type": "string", - "format": "uuid", - "description": "The prompt set this run was created from.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "results": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EvalRunResult" - }, - "description": "Per-prompt results for this run, ordered by their creation order in the prompt set." - }, - "run_number": { - "type": "integer", - "description": "Sequential, per-prompt-set run number.", - "example": 3 - }, - "status": { - "type": "string", - "enum": [ - "RUNNING", - "COMPLETE", - "CANCELLED" - ], - "description": "Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly once.", - "example": "RUNNING" - } - }, - "required": [ - "branch_id", - "branch_name", - "completed_at", - "created_at", - "description", - "id", - "is_archived", - "model_id", - "prompt_set_id", - "results", - "run_number", - "status" - ], - "description": "The newly created run with its initial results." - }, - "EvalRunResult": { - "type": "object", - "properties": { - "agentic_job": { - "$ref": "#/components/schemas/EvalRunResultAgenticJob" - }, - "ai_timing_ms": { - "type": [ - "integer", - "null" - ], - "description": "Strict main-agent LLM processing time in milliseconds \u2014 the measured model-call duration, excluding tool execution and subagent model calls (those count toward `tool_timing_ms`). Shown as \"AI time\" in the UI. Runs recorded before this was measured fall back to an approximation (`timing_ms` minus tool latency).", - "example": 4121 - }, - "cost": { - "type": [ - "number", - "null" - ], - "description": "Total LLM cost (USD) for this prompt, if available.", - "example": 0.0021 - }, - "error_reason": { - "type": [ - "string", - "null" - ], - "description": "Failure reason string for prompts whose underlying job failed.", - "example": null - }, - "expectation": { - "type": [ - "string", - "null" - ], - "description": "The prompt's expectation as of run creation (snapshotted, so later prompt edits don't change past runs), or null when none was set. The analysis judge scores the analysis against it.", - "example": "The top product by revenue should be Aniseed Syrup." - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the run result row.", - "example": "aa0e8400-e29b-41d4-a716-446655440005" - }, - "prompt": { - "type": "string", - "description": "The prompt text that was evaluated.", - "example": "What are the top 5 products by revenue?" - }, - "query_count": { - "type": [ - "integer", - "null" - ], - "description": "Number of warehouse queries the underlying job ran. Null for runs executed before this metric was recorded.", - "example": 4 - }, - "query_timing_ms": { - "type": [ - "integer", - "null" - ], - "description": "Total wall-clock time (milliseconds) the underlying job spent running warehouse queries \u2014 a proxy for query execution time. Null for runs executed before this metric was recorded.", - "example": 1800 - }, - "score": { - "type": [ - "number", - "null" - ], - "description": "Numeric judge score for this prompt result, if scoring ran.", - "example": 0.9 - }, - "scoring_cost": { - "type": [ - "number", - "null" - ], - "description": "Total LLM cost (USD) for scoring this prompt result.", - "example": 0.0004 - }, - "timing_ms": { - "type": [ - "integer", - "null" - ], - "description": "Total `/generate` wall-time in milliseconds \u2014 LLM processing plus inner-loop tool execution. `ai_timing_ms` and `tool_timing_ms` split this; warehouse query time is separate (`query_timing_ms`).", - "example": 4321 - }, - "tool_timing_ms": { - "type": [ - "integer", - "null" - ], - "description": "Inner-loop tool latency in milliseconds \u2014 time spent running tools the model invoked (model and field-value lookups, query planning), excluding the warehouse query itself (`query_timing_ms`). Null for runs recorded before per-tool latency was tracked.", - "example": 200 - } - }, - "required": [ - "agentic_job", - "ai_timing_ms", - "cost", - "error_reason", - "expectation", - "id", - "prompt", - "query_count", - "query_timing_ms", - "score", - "scoring_cost", - "timing_ms", - "tool_timing_ms" - ] - }, - "EvalRunResultAgenticJob": { - "type": "object", - "properties": { - "conversation_id": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Conversation the agentic job belongs to.", - "example": "770e8400-e29b-41d4-a716-446655440002" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Agentic job identifier.", - "example": "990e8400-e29b-41d4-a716-446655440004" - }, - "state": { - "type": "string", - "enum": [ - "CANCELLED", - "COMPLETE", - "DELIVERING", - "EXECUTING", - "FAILED", - "QUEUED" - ], - "description": "Current state of the agentic job that ran this prompt.", - "example": "COMPLETE" - } - }, - "required": [ - "conversation_id", - "id", - "state" - ] - }, - "EvalApiError429": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Too many active runs; wait for an in-flight run to finish" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 429 - } - }, - "required": [ - "detail", - "status" - ] - }, - "EvalApiError503": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "AI eval is paused for this organization" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 503 - } - }, - "required": [ - "detail", - "status" - ] - }, - "EvalRunsCreateBody": { - "type": "object", - "properties": { - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 1024, - "description": "Optional human-readable description for the run. Pass `null` to clear (or omit). Max 1024 characters.", - "example": "Re-running after switching to gpt-4o for query generation" - }, - "prompt_set_id": { - "type": "string", - "format": "uuid", - "description": "The prompt set to execute.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "run_config": { - "type": "object", - "properties": { - "branch_id": { - "type": "string", - "format": "uuid", - "description": "Optional branch ID to run against. Must be a branch of the prompt set's model.", - "example": "440e8400-e29b-41d4-a716-446655440006" - } - }, - "description": "Per-run configuration. Optional \u2014 omit if no overrides." - } - }, - "required": [ - "prompt_set_id" - ] - }, - "EvalRunsGetResponse": { - "type": "object", - "properties": { - "run": { - "$ref": "#/components/schemas/EvalRunDetail" - } - }, - "required": [ - "run" - ] - }, - "EvalRunsDeleteResponse": { - "type": "object", - "properties": { - "is_archived": { - "type": "boolean", - "enum": [ - true - ], - "description": "Always `true` on success \u2014 the run has been archived." - } - }, - "required": [ - "is_archived" - ] - }, - "EvalRunsCancelResponse": { - "type": "object", - "properties": { - "cancelled": { - "type": "integer", - "description": "Number of per-prompt agentic jobs that were cancelled by this request.", - "example": 4 - }, - "run": { - "$ref": "#/components/schemas/EvalRunDetail" - }, - "total": { - "type": "integer", - "description": "Total number of per-prompt jobs in the run.", - "example": 12 - } - }, - "required": [ - "cancelled", - "run", - "total" - ] - }, - "EvalRunsUnarchiveResponse": { - "type": "object", - "properties": { - "is_archived": { - "type": "boolean", - "enum": [ - false - ], - "description": "Always `false` on success \u2014 the run has been unarchived." - } - }, - "required": [ - "is_archived" - ] - }, - "FoldersListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "type": "object", - "properties": { - "_count": { - "type": "object", - "properties": { - "documents": { - "type": "number", - "description": "Number of documents in the folder" - }, - "favorites": { - "type": "number", - "description": "Number of users who have favorited this folder" - } - }, - "required": [ - "documents", - "favorites" - ], - "description": "Count statistics for the folder" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique folder identifier" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels associated with the folder" - }, - "name": { - "type": "string", - "description": "Name of the folder", - "example": "My Reports" - }, - "ownerId": { - "type": "string", - "format": "uuid", - "description": "User ID of the folder owner" - }, - "path": { - "type": "string", - "description": "Full path to the folder", - "example": "/shared/reports/my-reports" - }, - "url": { - "type": "string", - "description": "URL to view the folder in the Omni UI.", - "example": "https://org.omni.co/f/my-reports" - } - }, - "required": [ - "id", - "name", - "ownerId", - "path", - "url" - ] - }, - "description": "List of folders" - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "FoldersCreateResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "ID of the created folder" - }, - "name": { - "type": "string", - "description": "Name of the created folder" - }, - "ownerId": { - "type": "string", - "format": "uuid", - "description": "User ID of the folder owner" - }, - "path": { - "type": "string", - "description": "Full path to the folder" - }, - "scope": { - "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Share scope of the folder" - } - }, - "required": [ - "id", - "name", - "ownerId", - "path", - "scope" - ] - }, - "FoldersCreateBody": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "Name of the folder to create", - "example": "My New Folder" - }, - "parentFolderId": { - "type": "string", - "format": "uuid", - "description": "Parent folder ID (omit to create at root level)" - }, - "scope": { - "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Share scope for the folder" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "User ID to create the folder as (for org-scoped API keys only)" - } - }, - "required": [ - "name" - ] - }, - "FoldersDeleteResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the folder was deleted successfully" - } - }, - "required": [ - "success" - ] - }, - "FoldersUpdateResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Folder ID" - }, - "name": { - "type": "string", - "description": "Updated folder name" - }, - "path": { - "type": "string", - "description": "Updated URL path segment for the folder (the folder's own segment only)" - } - }, - "required": [ - "id", - "name", - "path" - ] - }, - "FoldersUpdateBody": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "New display name for the folder", - "example": "Q1 Reports" - }, - "path": { - "type": "string", - "minLength": 1, - "pattern": "^[a-zA-Z0-9-]+$", - "description": "New URL path segment for the folder (alphanumeric and dashes only). This is only the folder's own segment, not the full hierarchical path.", - "example": "q1-reports" - }, - "resolvePathConflict": { - "type": "boolean", - "default": false, - "description": "When true, automatically resolves path collisions with existing folders by appending a numeric suffix (e.g., my-path-1). When false (default), returns 409 Conflict if the path is already taken. Does not apply to reserved paths, which are always rejected with 400." - } - } - }, - "FoldersGetPermissionsResponse": { - "type": "object", - "properties": { - "permits": { - "type": "array", - "items": { - "type": "object", - "properties": { - "accessBoost": { - "type": "boolean", - "description": "Whether access boost is enabled for this permit" - }, - "role": { - "type": "string", - "description": "Content role (e.g., VIEWER, EDITOR, MANAGER)", - "example": "VIEWER" - }, - "userGroupId": { - "type": "string", - "description": "User group ID if this is a group permit" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "User ID if this is a user permit" - } - }, - "required": [ - "role" - ] - }, - "description": "List of permission permits for the folder" - } - }, - "required": [ - "permits" - ] - }, - "FoldersAddPermissionsResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were added successfully" - } - }, - "required": [ - "success" - ] - }, - "FoldersAddPermissionsBody": { - "type": "object", - "properties": { - "accessBoost": { - "type": "boolean", - "default": false, - "description": "Whether to grant access boost" - }, - "role": { - "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "EXPLORER", - "EDITOR", - "MANAGER" - ], - "description": "Content role to assign (VIEWER, EDITOR, or MANAGER)", - "example": "VIEWER" - }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to grant permission to" - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to grant permission to" - } - }, - "required": [ - "role" - ], - "additionalProperties": false - }, - "FoldersUpdatePermissionsResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were updated successfully" - } - }, - "required": [ - "success" - ] - }, - "FoldersUpdatePermissionsBody": { - "type": "object", - "properties": { - "accessBoost": { - "type": "boolean", - "description": "Whether to grant access boost" - }, - "role": { - "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "EXPLORER", - "EDITOR", - "MANAGER" - ], - "description": "New content role to assign" - }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to update permissions for" - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to update permissions for" - } - }, - "additionalProperties": false - }, - "FoldersRevokePermissionsResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were revoked successfully" - } - }, - "required": [ - "success" - ] - }, - "FoldersRevokePermissionsBody": { - "type": "object", - "properties": { - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to revoke permissions from" - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to revoke permissions from" - } - }, - "additionalProperties": false - }, - "LabelsListResponse": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" - }, - "name": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" - }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" - } - }, - "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" - ] - }, - "description": "List of labels" - } - }, - "required": [ - "labels" - ] - }, - "LabelsCreateResponse": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" - }, - "name": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" - }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" - } - }, - "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" - ] - }, - "LabelsCreateBody": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "default": null, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "default": null, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "default": false, - "description": "Show label on homepage. Requires admin permissions." - }, - "name": { - "type": "string", - "minLength": 2, - "maxLength": 25, - "description": "Label name", - "example": "important" - }, - "verified": { - "type": "boolean", - "default": false, - "description": "Mark as verified label. Requires admin permissions." - } - }, - "required": [ - "name" - ] - }, - "LabelsGetResponse": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" - }, - "name": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" - }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" - } - }, - "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" - ] - }, - "LabelsUpdateResponse": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" - }, - "name": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" - }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" - } - }, - "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" - ] - }, - "LabelsUpdateBody": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Show label on homepage. Requires admin permissions to modify." - }, - "name": { - "type": "string", - "minLength": 2, - "maxLength": 25, - "description": "Label name", - "example": "important" - }, - "verified": { - "type": "boolean", - "description": "Mark as verified label. Requires admin permissions to modify." - } - } - }, - "ModelSuggestionsListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ModelSuggestion" - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "ModelSuggestion": { - "type": "object", - "properties": { - "aiModifiedAt": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp of the last AI write (create or AI update). Unaffected by dismiss/restore." - }, - "category": { - "type": "string", - "description": "Suggestion category, e.g. `missing_context`.", - "example": "missing_context" - }, - "createdAt": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp of when the suggestion was created." - }, - "evidence": { - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/components/schemas/SuggestionEvidenceItem" - }, - "description": "Source evidence for the suggestion. Null for rows created before evidence was tracked; `[]` when none was cited." - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the suggestion." - }, - "ignoreReason": { - "type": [ - "string", - "null" - ], - "description": "Optional free-text reason recorded when the suggestion was dismissed." - }, - "ignoredAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "ISO 8601 timestamp of dismissal, or null if active." - }, - "ignoredBy": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "User id that dismissed the suggestion, or null if active." - }, - "priority": { - "type": "integer", - "minimum": 1, - "maximum": 10, - "description": "Priority from 1 (highest) to 10 (lowest).", - "example": 1 - }, - "proposedChanges": { - "$ref": "#/components/schemas/SuggestionProposedChanges" - }, - "rationale": { - "type": "string", - "description": "Explanation of why the suggestion was made." - }, - "title": { - "type": "string", - "description": "Short human-readable title." - }, - "updatedAt": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 timestamp of the last write of any kind, including dismiss/restore." - } - }, - "required": [ - "aiModifiedAt", - "category", - "createdAt", - "evidence", - "id", - "ignoreReason", - "ignoredAt", - "ignoredBy", - "priority", - "proposedChanges", - "rationale", - "title", - "updatedAt" - ] - }, - "SuggestionEvidenceItem": { - "type": "object", - "properties": { - "capturedAt": { - "type": "string", - "description": "ISO 8601 timestamp of when the evidence was captured." - }, - "chatAiSessionId": { - "type": "string", - "format": "uuid", - "description": "Chat session that motivated the suggestion." - }, - "type": { - "type": "string", - "enum": [ - "ai_chat" - ] - } - }, - "required": [ - "capturedAt", - "chatAiSessionId", - "type" - ] - }, - "SuggestionProposedChanges": { - "type": "object", - "properties": { - "edits": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SuggestionContextEdit" - } - }, - "kind": { - "type": "string", - "enum": [ - "context_edits" - ] - } - }, - "required": [ - "edits", - "kind" - ], - "description": "The change(s) the suggestion would apply to the model." - }, - "SuggestionContextEdit": { - "type": "object", - "properties": { - "field": { - "type": "string", - "description": "The model field being edited (e.g. `ai_context`).", - "example": "ai_context" - }, - "target": { - "type": "string", - "description": "Dot-path identifying what the edit applies to, e.g. `views.orders.fields.status`.", - "example": "views.orders" - }, - "value": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ], - "description": "The proposed value for the field." - } - }, - "required": [ - "field", - "target", - "value" - ] - }, - "ScheduleSuggestionsResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "The schedule (trigger) id." - }, - "sharedModelId": { - "type": "string", - "format": "uuid", - "description": "The shared model the schedule generates suggestions for." - }, - "status": { - "type": "string", - "enum": [ - "enabled" - ] - }, - "timezone": { - "type": "string", - "description": "IANA timezone the schedule runs in.", - "example": "America/New_York" - } - }, - "required": [ - "id", - "sharedModelId", - "status", - "timezone" - ] - }, - "ScheduleSuggestionsBody": { - "type": "object", - "properties": { - "timezone": { - "type": "string", - "default": "UTC", - "description": "IANA timezone the schedule fires in (e.g. `America/New_York`). Generation currently runs once daily at ~2 AM in this timezone. Defaults to `UTC`.", - "example": "America/New_York" - } - }, - "additionalProperties": false - }, - "IgnoreSuggestionBody": { - "type": "object", - "properties": { - "reason": { - "type": "string", - "maxLength": 4000, - "description": "Optional free-text reason for dismissing the suggestion.", - "example": "Already covered by an existing field description." - } - }, - "additionalProperties": false - }, - "ModelsListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseModelId": { - "type": [ - "string", - "null" - ], - "description": "Base model ID for branch/extension models" - }, - "branches": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Branch ID" - }, - "name": { - "type": "string", - "description": "Branch name" - } - }, - "required": [ - "id", - "name" - ] - }, - "description": "Active branches (if include=activeBranches)" - }, - "connectionId": { - "type": [ - "string", - "null" - ], - "description": "Connection ID" - }, - "createdAt": { - "type": "string", - "description": "Creation timestamp" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Deletion timestamp" - }, - "id": { - "type": "string", - "description": "Model ID" - }, - "modelKind": { - "type": [ - "string", - "null" - ], - "description": "Model kind" - }, - "name": { - "type": [ - "string", - "null" - ], - "description": "Model name" - }, - "updatedAt": { - "type": "string", - "description": "Last update timestamp" - } - }, - "required": [ - "baseModelId", - "connectionId", - "createdAt", - "deletedAt", - "id", - "modelKind", - "name", - "updatedAt" - ] - }, - "description": "List of model records" - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "CreateModelSchemaBase": { - "type": "object", - "properties": { - "accessGrants": { - "type": "array", - "items": { - "type": "object", - "properties": { - "accessBoostable": { - "type": "boolean" - }, - "allowedValues": { - "type": "array", - "items": { - "type": "string" - } - }, - "codeComments": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "ignored": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "userAttribute": { - "type": "string" - } - }, - "required": [ - "accessBoostable", - "name" - ] - }, - "description": "Access grants for the model" - }, - "allowAsWorkbookBase": { - "type": "boolean", - "description": "Allow this model as a workbook base" - }, - "baseModelId": { - "type": "string", - "description": "Base model ID for extension or branch models" - }, - "connectionId": { - "type": "string", - "description": "Connection ID for the model" - }, - "modelKind": { - "anyOf": [ - { - "type": "string", - "enum": [ - "SCHEMA" - ] - }, - { - "type": "string", - "enum": [ - "SHARED" - ] - }, - { - "type": "string", - "enum": [ - "SHARED_EXTENSION" - ] - }, - { - "type": "string", - "enum": [ - "BRANCH" - ] - } - ], - "default": "SCHEMA", - "description": "Kind of model to create" - }, - "modelName": { - "type": "string", - "description": "Name for the model" - }, - "usesIsolatedBranches": { - "type": "boolean", - "description": "For SHARED_EXTENSION models, controls if branches are shown on extension model page instead of parent shared model" - } - }, - "required": [ - "connectionId" - ] - }, - "ModelsUpdateResponse": { - "type": "object", - "properties": { - "model": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Model ID" - }, - "name": { - "type": "string", - "description": "Updated model name" - } - }, - "required": [ - "id", - "name" - ], - "description": "Updated model details" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - } - }, - "required": [ - "model", - "success" - ] - }, - "ModelsUpdateBody": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "New name for the model", - "example": "My Renamed Model" - } - }, - "required": [ - "name" - ] - }, - "JobsGetStatusResponse": { - "type": "object", - "properties": { - "job_id": { - "type": "string", - "description": "The job ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "job_type": { - "type": "string", - "description": "The type of job (e.g., REFRESH_SCHEMA)", - "example": "REFRESH_SCHEMA" - }, - "status": { - "type": "string", - "enum": [ - "IN_PROGRESS", - "COMPLETED", - "FAILED" - ], - "description": "Current status of the job", - "example": "COMPLETED" - } - }, - "required": [ - "job_id", - "job_type", - "status" - ] - }, - "ModelsGetSchemasResponse": { - "type": "object", - "properties": { - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Sorted list of all available schema names (catalog-scoped if applicable, e.g. warehouse.reporting)" - } - }, - "required": [ - "schemas" - ] - }, - "ModelsGetViewResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "views": { - "type": "array", - "items": { - "type": "object", - "properties": { - "description": { - "type": "string", - "description": "View description" - }, - "fields": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Field name" - }, - "type": { - "type": "string", - "enum": [ - "dimension", - "measure", - "filter" - ], - "description": "Field type" - } - }, - "required": [ - "name", - "type" - ] - }, - "description": "Fields in the view" - }, - "hidden": { - "type": "boolean", - "description": "Whether the view is hidden" - }, - "label": { - "type": "string", - "description": "View label" - }, - "name": { - "type": "string", - "description": "View name" - } - }, - "required": [ - "fields", - "name" - ] - }, - "description": "List of views" - } - }, - "required": [ - "success", - "views" - ] - }, - "ModelsUpdateViewBody": { - "type": "object", - "properties": { - "aiContext": { - "type": "string", - "description": "AI context for the view" - }, - "description": { - "type": "string", - "description": "View description" - }, - "format": { - "type": "string", - "description": "View format" - }, - "hidden": { - "type": "boolean", - "description": "Whether the view is hidden" - }, - "label": { - "type": "string", - "description": "View label" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the view" - } - } - }, - "ModelsUpdateFieldBody": { - "type": "object", - "properties": { - "aiContext": { - "type": "string", - "description": "AI context for the field" - }, - "allValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Deprecated: use sampleValues instead" - }, - "binBoundaries": { - "type": "array", - "items": { - "type": "number" - }, - "description": "Bin boundaries for binned fields" - }, - "binLabels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels for bins" - }, - "description": { - "type": "string", - "description": "Field description" - }, - "drillFields": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Drill-down fields" - }, - "elseValue": { - "type": "string", - "description": "Else value for grouped fields" - }, - "filters": { - "type": "object", - "additionalProperties": {}, - "description": "Filters for the field" - }, - "format": { - "type": "string", - "description": "Field format" - }, - "groupFilters": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": {} - }, - "description": "Group filters" - }, - "groupLabel": { - "type": "string", - "description": "Group label" - }, - "groupNames": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Group names" - }, - "hidden": { - "type": "boolean", - "description": "Whether the field is hidden" - }, - "ignored": { - "type": "boolean", - "description": "Whether the field is ignored" - }, - "isCalc": { - "type": "boolean", - "description": "Whether this is a calculation field" - }, - "label": { - "type": "string", - "description": "Field label" - }, - "newFieldName": { - "type": "string", - "description": "New field name (for rename)" - }, - "newViewName": { - "type": "string", - "description": "New view name (for move)" - }, - "sampleValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Sample values for the field" - }, - "sql": { - "type": "string", - "description": "SQL expression for the field" - }, - "synonyms": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Synonyms for the field" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the field" - }, - "topicContext": { - "type": "string", - "description": "Topic context for the field" - } - } - }, - "ModelsListTopicsResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "topics": { - "type": "array", - "items": { - "type": "object", - "properties": { - "base_view_name": { - "type": "string", - "description": "Base view name for the topic" - }, - "description": { - "type": "string", - "description": "Topic description" - }, - "group_label": { - "type": "string", - "description": "Group label" - }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" - }, - "label": { - "type": "string", - "description": "Topic label" - }, - "name": { - "type": "string", - "description": "Topic name" - } - }, - "required": [ - "base_view_name", - "name" - ] - }, - "description": "List of topics" - } - }, - "required": [ - "success", - "topics" - ] - }, - "ModelsGetTopicResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "topic": { - "type": "object", - "properties": { - "base_view_name": { - "type": "string", - "description": "Base view name for the topic" - }, - "description": { - "type": "string", - "description": "Topic description" - }, - "group_label": { - "type": "string", - "description": "Group label" - }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" - }, - "label": { - "type": "string", - "description": "Topic label" - }, - "name": { - "type": "string", - "description": "Topic name" - }, - "relationships": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": {} - }, - "description": "Relationships for the topic" - }, - "views": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": {} - }, - "description": "Views available in the topic" - } - }, - "required": [ - "base_view_name", - "name", - "relationships", - "views" - ], - "description": "Topic details with relationships and views" - } - }, - "required": [ - "success", - "topic" - ] - }, - "ModelsUpdateTopicBody": { - "type": "object", - "properties": { - "description": { - "type": "string", - "description": "Topic description" - }, - "groupLabel": { - "type": "string", - "description": "Group label for the topic" - }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" - }, - "label": { - "type": "string", - "description": "Topic label" - }, - "newTopicName": { - "type": "string", - "description": "New topic name (for rename)" - } - } - }, - "ModelsCreateFieldBody": { - "type": "object", - "properties": { - "aggregateType": { - "type": "string", - "enum": [ - "AVERAGE", - "COUNT", - "COUNT_DISTINCT", - "LIST", - "MAX", - "MIN", - "SUM", - "MEDIAN", - "PERCENTILE", - "AVERAGE_DISTINCT_ON", - "SUM_DISTINCT_ON", - "MEDIAN_DISTINCT_ON", - "PERCENTILE_DISTINCT_ON", - "SEMANTIC_VIEW_AGG" - ], - "description": "Aggregate type for measures. Setting this property promotes the field to a measure (written under `measures:`); omit it to create a dimension (written under `dimensions:`). Values must be uppercase canonical names.", - "example": "SUM" - }, - "aiContext": { - "type": "string", - "description": "AI context for the field" - }, - "description": { - "type": "string", - "description": "Field description" - }, - "fieldName": { - "type": "string", - "description": "Field name", - "example": "total_revenue" - }, - "format": { - "type": "string", - "description": "Field format" - }, - "hidden": { - "type": "boolean", - "description": "Whether the field is hidden" - }, - "label": { - "type": "string", - "description": "Field label" - }, - "sql": { - "type": "string", - "description": "SQL expression for the field" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the field" - }, - "topicContext": { - "type": "string", - "description": "Topic context for topic-scoped fields" - }, - "viewName": { - "type": "string", - "description": "View to add the field to", - "example": "orders" - } - }, - "required": [ - "fieldName", - "viewName" - ], - "additionalProperties": false - }, - "ModelsRefreshResponse": { - "type": "object", - "properties": { - "jobId": { - "type": "string", - "description": "Job ID for the refresh operation" - }, - "modelId": { - "type": "string", - "description": "Model ID being refreshed" - }, - "status": { - "type": "string", - "enum": [ - "running", - "completed", - "failed" - ], - "description": "Current status of the refresh" - } - }, - "required": [ - "jobId", - "modelId", - "status" - ] - }, - "ModelsValidateResponse": { - "type": "object", - "properties": { - "issues": { - "type": "array", - "items": { - "type": "object", - "properties": { - "field": { - "type": "string", - "description": "Field name with the issue" - }, - "message": { - "type": "string", - "description": "Validation issue message" - }, - "severity": { - "type": "string", - "enum": [ - "error", - "warning" - ], - "description": "Issue severity" - }, - "view": { - "type": "string", - "description": "View name with the issue" - } - }, - "required": [ - "message", - "severity" - ] - }, - "description": "List of validation issues" - }, - "valid": { - "type": "boolean", - "description": "Whether the model is valid" - } - }, - "required": [ - "issues", - "valid" - ] - }, - "ModelsMigrateBody": { - "type": "object", - "properties": { - "branchName": { - "type": "string", - "description": "Branch name for the target model" - }, - "commitMessage": { - "type": "string", - "description": "Commit message for git sync" - }, - "deleteViewsAndTopicsMissingFromSource": { - "type": "boolean", - "default": true, - "description": "When true (default), views and topics in the target model that are missing from the migrated source are deleted (the source is treated as the complete model). When false, they are kept (inherited) instead \u2014 useful when the source git ref may be missing objects that exist in omni but not in git, e.g. a newly synced schema." - }, - "gitRef": { - "type": "string", - "description": "Git reference" - }, - "targetModelId": { - "type": "string", - "format": "uuid", - "description": "Target model ID to migrate to" - } - }, - "required": [ - "targetModelId" - ] - }, - "ModelsDbtExposuresResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DbtExposureWithMeta" - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "DbtExposureWithMeta": { - "type": "object", - "properties": { - "dashboard_identifier": { - "type": "string", - "description": "Identifier of the dashboard that generated this exposure" - }, - "deduplication_name": { - "type": "string", - "description": "A unique name for this exposure. Use this instead of exposure.name to avoid duplicate names, or use it as a fallback when exposure.name collides with another exposure." - }, - "exposure": { - "$ref": "#/components/schemas/DbtExposure" - } - }, - "required": [ - "dashboard_identifier", - "deduplication_name", - "exposure" - ] - }, - "DbtExposure": { - "type": "object", - "properties": { - "depends_on": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of dbt model references (e.g. ref('model_name'))", - "example": [ - "ref('orders')", - "ref('customers')" - ] - }, - "label": { - "type": "string", - "description": "Original dashboard name" - }, - "name": { - "type": "string", - "description": "Sanitized exposure name. May contain duplicates across exposures; use deduplication_name for a guaranteed-unique alternative.", - "example": "my_dashboard" - }, - "owner": { - "$ref": "#/components/schemas/DbtExposureOwner" - }, - "type": { - "type": "string", - "enum": [ - "dashboard", - "notebook", - "analysis", - "ml", - "application" - ], - "description": "Type of the exposure", - "example": "dashboard" - }, - "url": { - "type": "string", - "description": "URL of the dashboard" - } - }, - "required": [ - "depends_on", - "name", - "owner", - "type" - ], - "description": "The dbt exposure for this dashboard." - }, - "DbtExposureOwner": { - "type": "object", - "properties": { - "email": { - "type": "string", - "description": "Email of the dashboard owner" - }, - "name": { - "type": "string", - "description": "Name of the dashboard owner" - } - }, - "required": [ - "email", - "name" - ] - }, - "ModelsBranchDbtBody": { - "type": "object", - "properties": { - "dbt_environment_id": { - "type": "string", - "format": "uuid", - "description": "ID of the dbt environment to activate on this branch", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "dbt_git_branch": { - "type": "string", - "description": "Git branch to associate with the dbt environment", - "example": "feature/new-metrics" - } - }, - "required": [ - "dbt_environment_id" - ] - }, - "JobCreatedResponse": { - "type": "object", - "properties": { - "jobId": { - "type": "string", - "description": "ID of the created job. Poll GET /api/v1/jobs/{jobId}/status for its status.", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "jobId" - ] - }, - "ModelsMergeBranchResponse": { - "type": "object", - "properties": { - "failed_drafts_count": { - "type": "number", - "description": "Number of drafts that failed to publish" - }, - "git_synced": { - "type": "boolean", - "description": "Whether git was synced" - }, - "published_drafts_count": { - "type": "number", - "description": "Number of drafts published" - }, - "success": { - "type": "boolean", - "description": "Whether the merge succeeded" - } - }, - "required": [ - "failed_drafts_count", - "git_synced", - "published_drafts_count", - "success" - ] - }, - "ModelsMergeBranchBody": { - "type": "object", - "properties": { - "commit_message": { - "type": "string", - "description": "Custom commit message for git sync" - }, - "delete_branch": { - "type": "boolean", - "default": false, - "description": "Delete the branch after merging" - }, - "force_override_git_settings": { - "type": "boolean", - "default": false, - "description": "Override PR-required or git-follower settings" - }, - "publish_drafts": { - "type": "boolean", - "default": true, - "description": "Publish branch-attached drafts" - } - } - }, - "ModelsCommitResponse": { - "type": "object", - "properties": { - "did_sync": { - "type": "boolean", - "description": "Whether a sync operation was performed against git" - }, - "git_sha": { - "type": [ - "string", - "null" - ], - "description": "The git SHA of the commit that was pushed (null if no commit was needed)" - }, - "in_sync": { - "type": "boolean", - "description": "Whether the branch is in sync with git after the operation" - }, - "pr_url": { - "type": [ - "string", - "null" - ], - "description": "The URL of the pull request (or PR creation page for newly-created PRs). May be null when the underlying git provider is not recognized." - } - }, - "required": [ - "did_sync", - "git_sha", - "in_sync", - "pr_url" - ] - }, - "ModelsCommitBody": { - "type": "object", - "properties": { - "allow_branch_exists": { - "type": "boolean", - "default": true, - "description": "If true (default), the commit succeeds whether the git branch already exists or not. If false, the request fails when the git branch already exists \u2014 use this to ensure only new pull requests are created. Cannot be false when require_branch_exists is true.", - "example": true - }, - "branch_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the branch to commit.", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "commit_message": { - "type": "string", - "minLength": 1, - "description": "Commit message for the git commit.", - "example": "Add new orders view" - }, - "require_branch_exists": { - "type": "boolean", - "default": false, - "description": "If true, the request fails when the git branch does not already exist \u2014 use this to ensure only existing pull requests are updated. Defaults to false. Cannot be true when allow_branch_exists is false.", - "example": false - } - }, - "required": [ - "branch_id", - "commit_message" - ] - }, - "ModelsCacheResetResponse": { - "type": "object", - "properties": { - "cache_reset": { - "type": "object", - "properties": { - "created_at": { - "type": [ - "string", - "null" - ], - "description": "Creation timestamp" - }, - "model_id": { - "type": "string", - "description": "Model ID" - }, - "policy_name": { - "type": "string", - "description": "Cache policy name" - }, - "reset_at": { - "type": [ - "string", - "null" - ], - "description": "Reset timestamp" - }, - "updated_at": { - "type": [ - "string", - "null" - ], - "description": "Last update timestamp" - } - }, - "required": [ - "created_at", - "model_id", - "policy_name", - "reset_at", - "updated_at" - ], - "description": "Cache reset details" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - } - }, - "required": [ - "cache_reset", - "success" - ] - }, - "ModelsCacheResetBody": { - "type": "object", - "properties": { - "resetAt": { - "type": "string", - "description": "ISO-8601 timestamp for when to reset the cache", - "example": "2024-01-15T12:00:00Z" - } - } - }, - "ModelsGitGetResponse": { - "type": "object", - "properties": { - "authMethod": { - "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", - "example": "ssh" - }, - "baseBranch": { - "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", - "example": false - }, - "cloneUrl": { - "type": "string", - "description": "Clone URL of the git repository (SSH or HTTPS)", - "example": "git@github.com:org/repo.git" - }, - "gitFollower": { - "type": "boolean", - "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", - "example": false - }, - "gitServiceProvider": { - "type": "string", - "description": "The git provider type", - "example": "github" - }, - "modelPath": { - "type": [ - "string", - "null" - ], - "description": "Path to model files in the repository", - "example": "omni/my_model" - }, - "publicKey": { - "type": [ - "string", - "null" - ], - "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", - "example": "ssh-ed25519 AAAA..." - }, - "requirePullRequest": { - "type": "string", - "enum": [ - "always", - "users-only", - "never" - ], - "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", - "example": "users-only" - }, - "sshUrl": { - "type": "string", - "deprecated": true, - "description": "Deprecated \u2014 use cloneUrl. Clone URL of the git repository." - }, - "webUrl": { - "type": [ - "string", - "null" - ], - "description": "Custom web URL for the git repository, or null if not set", - "example": "https://github.com/org/repo" - }, - "webhookSecret": { - "type": "string", - "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" - }, - "webhookUrl": { - "type": "string", - "description": "Webhook URL to configure in your git provider", - "example": "https://app.omni.co/api/webhooks/model/..." - } - }, - "required": [ - "authMethod", - "baseBranch", - "branchPerPullRequest", - "cloneUrl", - "gitFollower", - "gitServiceProvider", - "modelPath", - "publicKey", - "requirePullRequest", - "sshUrl", - "webUrl", - "webhookUrl" - ] - }, - "ModelsGitCreateResponse": { - "type": "object", - "properties": { - "authMethod": { - "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", - "example": "ssh" - }, - "baseBranch": { - "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", - "example": false - }, - "cloneUrl": { - "type": "string", - "description": "Clone URL of the git repository (SSH or HTTPS)", - "example": "git@github.com:org/repo.git" - }, - "gitFollower": { - "type": "boolean", - "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", - "example": false - }, - "gitServiceProvider": { - "type": "string", - "description": "The git provider type", - "example": "github" - }, - "modelPath": { - "type": [ - "string", - "null" - ], - "description": "Path to model files in the repository", - "example": "omni/my_model" - }, - "publicKey": { - "type": [ - "string", - "null" - ], - "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", - "example": "ssh-ed25519 AAAA..." - }, - "requirePullRequest": { - "type": "string", - "enum": [ - "always", - "users-only", - "never" - ], - "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", - "example": "users-only" - }, - "sshUrl": { - "type": "string", - "deprecated": true, - "description": "Deprecated \u2014 use cloneUrl. Clone URL of the git repository." - }, - "webUrl": { - "type": [ - "string", - "null" - ], - "description": "Custom web URL for the git repository, or null if not set", - "example": "https://github.com/org/repo" - }, - "webhookSecret": { - "type": "string", - "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" - }, - "webhookUrl": { - "type": "string", - "description": "Webhook URL to configure in your git provider", - "example": "https://app.omni.co/api/webhooks/model/..." - } - }, - "required": [ - "authMethod", - "baseBranch", - "branchPerPullRequest", - "cloneUrl", - "gitFollower", - "gitServiceProvider", - "modelPath", - "publicKey", - "requirePullRequest", - "sshUrl", - "webUrl", - "webhookUrl" - ] - }, - "ModelsGitCreateBody": { - "type": "object", - "properties": { - "authMethod": { - "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "default": "ssh", - "description": "Authentication method. \"ssh\" for deploy key (default), \"https_token\" for deploy token/PAT.", - "example": "ssh" - }, - "baseBranch": { - "type": "string", - "default": "main", - "description": "The target branch for Omni pull requests. Defaults to \"main\"", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "default": false, - "description": "If true, all pull requests will create a branch in Omni. Defaults to false", - "example": false - }, - "cloneUrl": { - "type": "string", - "minLength": 1, - "description": "Clone URL of the git repository. SSH (git@...) for deploy key auth, HTTPS (https://...) for token auth.", - "example": "git@github.com:org/repo.git" - }, - "gitFollower": { - "type": "boolean", - "default": false, - "description": "If true, the shared model will be read-only. Defaults to false", - "example": false - }, - "gitServiceProvider": { - "type": "string", - "enum": [ - "github", - "gitlab", - "azure_devops", - "bitbucket", - "bitbucket_datacenter", - "auto" - ], - "default": "auto", - "description": "The git provider type. Use \"auto\" for automatic detection. Defaults to \"auto\"", - "example": "auto" - }, - "modelPath": { - "type": "string", - "description": "Path to model files in the repository. Defaults to omni/. Use a plain name (e.g., \"my_model\") for omni/my_model, or a leading slash for a custom path (e.g., \"/bi/models/sales\")", - "example": "my_model" - }, - "requirePullRequest": { - "type": "string", - "enum": [ - "always", - "users-only", - "never" - ], - "default": "never", - "description": "Controls when pull requests are required. Defaults to \"never\"", - "example": "never" - }, - "sshUrl": { - "type": "string", - "minLength": 1, - "description": "Deprecated \u2014 use cloneUrl. Clone URL of the git repository.", - "example": "git@github.com:org/repo.git", - "deprecated": true - }, - "token": { - "type": "string", - "maxLength": 1000, - "pattern": "^[a-zA-Z0-9_\\-.]+$", - "description": "HTTPS token for authentication (deploy token value, PAT, etc.). Required when authMethod is \"https_token\"." - }, - "webUrl": { - "type": "string", - "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", - "example": "https://github.com/org/repo" - } - } - }, - "ModelsGitUpdateResponse": { - "type": "object", - "properties": { - "authMethod": { - "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", - "example": "ssh" - }, - "baseBranch": { - "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", - "example": false - }, - "cloneUrl": { - "type": "string", - "description": "Clone URL of the git repository (SSH or HTTPS)", - "example": "git@github.com:org/repo.git" - }, - "gitFollower": { - "type": "boolean", - "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", - "example": false - }, - "gitServiceProvider": { - "type": "string", - "description": "The git provider type", - "example": "github" - }, - "modelPath": { - "type": [ - "string", - "null" - ], - "description": "Path to model files in the repository", - "example": "omni/my_model" - }, - "publicKey": { - "type": [ - "string", - "null" - ], - "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", - "example": "ssh-ed25519 AAAA..." - }, - "requirePullRequest": { - "type": "string", - "enum": [ - "always", - "users-only", - "never" - ], - "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", - "example": "users-only" - }, - "sshUrl": { - "type": "string", - "deprecated": true, - "description": "Deprecated \u2014 use cloneUrl. Clone URL of the git repository." - }, - "webUrl": { - "type": [ - "string", - "null" - ], - "description": "Custom web URL for the git repository, or null if not set", - "example": "https://github.com/org/repo" - }, - "webhookSecret": { - "type": "string", - "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" - }, - "webhookUrl": { - "type": "string", - "description": "Webhook URL to configure in your git provider", - "example": "https://app.omni.co/api/webhooks/model/..." - } - }, - "required": [ - "authMethod", - "baseBranch", - "branchPerPullRequest", - "cloneUrl", - "gitFollower", - "gitServiceProvider", - "modelPath", - "publicKey", - "requirePullRequest", - "sshUrl", - "webUrl", - "webhookUrl" - ] - }, - "ModelsGitUpdateBody": { - "type": "object", - "properties": { - "authMethod": { - "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "description": "Authentication method to change to.", - "example": "ssh" - }, - "baseBranch": { - "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni", - "example": false - }, - "cloneUrl": { - "type": "string", - "minLength": 1, - "description": "Clone URL of the git repository (SSH or HTTPS).", - "example": "git@github.com:org/repo.git" - }, - "gitFollower": { - "type": "boolean", - "description": "If true, the shared model will be read-only", - "example": false - }, - "gitServiceProvider": { - "type": "string", - "enum": [ - "github", - "gitlab", - "azure_devops", - "bitbucket", - "bitbucket_datacenter", - "auto" - ], - "description": "The git provider type", - "example": "github" - }, - "modelPath": { - "type": "string", - "description": "Path to model files in the repository", - "example": "my_model" - }, - "requirePullRequest": { - "type": "string", - "enum": [ - "always", - "users-only", - "never" - ], - "description": "Controls when pull requests are required", - "example": "users-only" - }, - "sshUrl": { - "type": "string", - "minLength": 1, - "description": "Deprecated \u2014 use cloneUrl. Clone URL of the git repository.", - "example": "git@github.com:org/repo.git", - "deprecated": true - }, - "token": { - "type": "string", - "maxLength": 1000, - "pattern": "^[a-zA-Z0-9_\\-.]+$", - "description": "HTTPS token for authentication (deploy token value, PAT, etc.)." - }, - "webUrl": { - "type": "string", - "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", - "example": "https://github.com/org/repo" - } - } - }, - "ModelsGitDeleteResponse": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Success message", - "example": "Git repository unlinked successfully" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "message", - "success" - ] - }, - "ModelsGitSyncResponse": { - "type": "object", - "properties": { - "didSync": { - "type": "boolean", - "description": "Whether a sync operation was performed" - }, - "gitSha": { - "type": [ - "string", - "null" - ], - "description": "The git SHA after the sync operation" - }, - "inSync": { - "type": "boolean", - "description": "Whether the model is currently in sync with git" - }, - "message": { - "type": "string", - "description": "Human-readable message about the sync status" - } - }, - "required": [ - "didSync", - "gitSha", - "inSync", - "message" - ] - }, - "ModelsGitSyncBody": { - "type": "object", - "properties": { - "commitMessage": { - "type": "string", - "description": "Optional commit message for the git sync operation", - "example": "Update model schema" - } - } - }, - "ModelsContentValidatorGetResponse": { - "type": "object", - "properties": { - "branch": { - "type": [ - "object", - "null" - ], - "properties": { - "id": { - "type": "string", - "description": "Branch UUID" - }, - "name": { - "type": "string", - "description": "Branch name" - } - }, - "required": [ - "id", - "name" - ], - "description": "Branch info (present if branch_id was specified)" - }, - "content": { - "type": "array", - "items": {}, - "description": "Documents with their validation results" - }, - "model_id": { - "type": "string", - "description": "Model UUID" - } - }, - "required": [ - "branch", - "content", - "model_id" - ] - }, - "ContentFilterMode": { - "type": "string", - "enum": [ - "ALL", - "WITH_ISSUES", - "NO_ISSUES" - ], - "description": "Filter documents by issue status. ALL (default) returns all documents with at least one query. WITH_ISSUES returns only documents with at least one query issue, dashboard filter issue, or document error. NO_ISSUES returns only documents with zero issues and no document errors." - }, - "ModelsContentValidatorReplaceResponse": { - "type": "object", - "properties": { - "replaced_dashboard_filters_count": { - "type": "integer", - "description": "Number of dashboard filters replaced" - }, - "replaced_documents_count": { - "type": "integer", - "description": "Number of documents modified" - }, - "replaced_input_column_keys_count": { - "type": "integer", - "description": "Number of input columns whose key references were replaced" - }, - "replaced_queries_count": { - "type": "integer", - "description": "Number of queries replaced" - }, - "replaced_workbook_models_count": { - "type": "integer", - "description": "Number of workbook models replaced" - }, - "skipped_pr_required_count": { - "type": "integer", - "description": "Number of documents skipped due to pull request requirements" - } - }, - "required": [ - "replaced_dashboard_filters_count", - "replaced_documents_count", - "replaced_input_column_keys_count", - "replaced_queries_count", - "replaced_workbook_models_count", - "skipped_pr_required_count" - ] - }, - "ModelsContentValidatorReplaceBody": { - "type": "object", - "properties": { - "branch_id": { - "type": "string", - "description": "Optional branch ID" - }, - "creator_id": { - "type": "string", - "format": "uuid", - "description": "Restrict replacement to documents created by this user (user ID). Unknown IDs return 400." - }, - "find": { - "type": "string", - "minLength": 1, - "description": "The string to find" - }, - "find_or_replace_type": { - "type": "string", - "enum": [ - "FIELD", - "TOPIC", - "VIEW" - ], - "description": "Type of find/replace operation." - }, - "folder_paths": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Restrict replacement to documents in matching folder paths (prefix match). Documents with no folder are excluded unless \"\" is specified." - }, - "include_personal_folders": { - "type": "boolean", - "default": false, - "description": "Whether to include personal folders" - }, - "labels": { - "type": "string", - "description": "Comma-separated label names to scope replacement. Unknown labels return 400." - }, - "only_in_workbook_id": { - "type": "string", - "description": "Optional workbook ID to limit the replace scope" - }, - "replacement": { - "type": "string", - "minLength": 1, - "description": "The replacement string" - } - }, - "required": [ - "find", - "find_or_replace_type", - "replacement" - ] - }, - "ModelYamlResponse": { - "type": "object", - "properties": { - "checksums": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Checksums for each file" - }, - "files": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "YAML content for each file" - }, - "version": { - "type": "number", - "description": "Model version number" - }, - "viewNames": { - "type": "object", - "additionalProperties": {}, - "description": "View name mappings" - } - }, - "required": [ - "files", - "version" - ] - }, - "ModelYamlCreateRequestBody": { - "type": "object", - "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Branch ID for branch-aware operations" - }, - "fileName": { - "type": "string", - "minLength": 1, - "description": "File name to create or update" - }, - "mode": { - "type": "string", - "enum": [ - "combined", - "extension", - "staged", - "merged", - "fully-resolved" - ], - "default": "combined", - "description": "IDE mode for YAML operations" - }, - "commitMessage": { - "type": "string", - "description": "Commit message for git sync" - }, - "fetchedAtMillis": { - "type": "number", - "description": "Timestamp when the file was fetched" - }, - "fullyResolved": { - "type": "boolean", - "default": false, - "description": "Treat the posted YAML as fully resolved (with the extends chain expanded). Only valid with mode=combined." - }, - "previousChecksum": { - "type": "string", - "description": "Previous checksum for conflict detection" - }, - "yaml": { - "type": "string", - "description": "YAML content for the file" - } - }, - "required": [ - "fileName", - "yaml" - ], - "additionalProperties": false - }, - "AiAgentActionsResponse": { - "type": "object", - "properties": { - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AiAgentAction" - }, - "description": "AI agent actions in display order: sample queries first, then skills. Topic-level entries follow model-level ones, and skills are deduped by id with topic skills winning over model skills." - } - }, - "required": [ - "records" - ] - }, - "AiAgentAction": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "enum": [ - "sample", - "skill" - ], - "description": "Source of the entry: `sample` for `sample_queries` (model- or topic-level) and `skill` for `skills` (model- or topic-level).", - "example": "skill" - }, - "label": { - "type": "string", - "description": "Short, human-readable name for the action \u2014 chip text in client UIs and the visible \"prompt\" on the answer card.", - "example": "Revenue trends" - }, - "prompt": { - "type": "string", - "description": "Submit this string verbatim as the `prompt` on `POST /api/v1/ai/jobs`. For sample queries this is the raw prompt; for skills it is a pre-formatted wrapper around the skill's input.", - "example": "Skill:\nShow me the recent revenue trends grouped by month\u2026" - } - }, - "required": [ - "kind", - "label", - "prompt" - ] - }, - "QueryRunResponse": { - "type": "object", - "properties": { - "completedQueries": { - "type": "array", - "items": {}, - "description": "Queries that completed synchronously with their results." - }, - "jobIds": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Job IDs for queries running asynchronously. Use /api/v1/query/wait to poll for results.", - "example": [ - "job_abc123", - "job_def456" - ] - }, - "plan": { - "description": "Query execution plan (only present if planOnly is true)." - } - } - }, - "QueryTimeoutResponse": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Error message indicating the query timed out.", - "example": "Query timed out" - }, - "remaining_job_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Job IDs for queries that have not yet completed. Use /api/v1/query/wait to poll for results." - }, - "timed_out": { - "type": "boolean", - "enum": [ - true - ], - "description": "Always true for timeout responses.", - "example": true - } - }, - "required": [ - "detail", - "timed_out" - ] - }, - "QueryRunBody": { - "type": "object", - "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Optional model branch to run the query against. Must belong to the same shared model as the query. When omitted, the query runs against the shared model. Takes precedence over the legacy `?branch_id=` URL query parameter.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "cache": { - "type": "string", - "enum": [ - "disabled", - "normal", - "refresh", - "refresh_all" - ], - "description": "Cache policy for query execution. Controls whether to use cached results.", - "example": "normal" - }, - "environmentConnectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID of the environment to run the query against, overriding the connection environment inherited from the (target) user's session or default. Must be a configured environment of the query model's connection that the user can access.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "formatResults": { - "type": "boolean", - "description": "Whether to format result values (e.g., apply number formatting). Only valid when resultType is specified." - }, - "planOnly": { - "type": "boolean", - "default": false, - "description": "If true, returns only the query execution plan without running the query." - }, - "query": { - "description": "The semantic query definition including fields, filters, sorts, and other query parameters." - }, - "resultType": { - "type": "string", - "enum": [ - "csv", - "json", - "xlsx" - ], - "description": "Output format for the results. If not specified, returns base64-encoded Arrow format." - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "Alternate location for the `?userId=` query parameter. Prefer the query parameter \u2014 this body field exists for backwards compatibility. Supplying both forms results in a 400. Only valid for org-scoped API keys; when set, the user's attributes are applied for row-level security and connection-environment switching.", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - } - }, - "QueryWaitResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": {}, - "description": "Array of completed query results. Each result contains the query data or an error." - } - }, - "required": [ - "results" - ] - }, - "SchedulesListItem": { - "type": "object", - "properties": { - "alert": { - "type": "object", - "properties": { - "conditionQueryName": { - "type": [ - "string", - "null" - ], - "description": "Name of the query used for alert condition" - }, - "conditionType": { - "type": "string", - "description": "Type of alert condition: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" - } - }, - "required": [ - "conditionQueryName", - "conditionType" - ], - "description": "Alert configuration (only present for alert-type schedules)" - }, - "content": { - "type": "string", - "description": "Content type: dashboard or tile", - "example": "dashboard" - }, - "dashboardName": { - "type": "string", - "description": "Name of the dashboard", - "example": "Weekly Sales Report" - }, - "destinationType": { - "type": "string", - "description": "Delivery destination type: email, slack, webhook, sftp, s3, google_sheets", - "example": "email" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Timestamp when the schedule was paused (null if active)" - }, - "format": { - "type": "string", - "description": "Output format: pdf, png, csv, xlsx, json, link_only", - "example": "pdf" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the schedule" - }, - "identifier": { - "type": "string", - "description": "Dashboard identifier", - "example": "12db1a0a" - }, - "lastCompletedAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Timestamp of last completed delivery" - }, - "lastStatus": { - "type": [ - "string", - "null" - ], - "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" - }, - "name": { - "type": "string", - "description": "Name of the schedule", - "example": "Weekly Sales Report" - }, - "ownerId": { - "type": "string", - "format": "uuid", - "description": "User ID of the schedule owner" - }, - "ownerName": { - "type": "string", - "description": "Display name of the schedule owner", - "example": "John Doe" - }, - "recipientCount": { - "type": "number", - "description": "Number of recipients (-1 for non-email destinations)", - "example": 5 - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", - "example": "0 9 ? * MON *" - }, - "slackRecipientType": { - "type": [ - "string", - "null" - ], - "description": "Slack recipient type: Channel or Users (null for non-Slack)" - }, - "systemDisabledAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Timestamp when system disabled the schedule (null if not system-disabled)" - }, - "systemDisabledReason": { - "type": [ - "string", - "null" - ], - "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for the schedule", - "example": "America/New_York" - } - }, - "required": [ - "content", - "dashboardName", - "destinationType", - "disabledAt", - "format", - "id", - "identifier", - "lastCompletedAt", - "lastStatus", - "name", - "ownerId", - "ownerName", - "recipientCount", - "schedule", - "slackRecipientType", - "systemDisabledAt", - "systemDisabledReason", - "timezone" - ] - }, - "SchedulesGetResponse": { - "type": "object", - "properties": { - "conditionQueryMapKey": { - "type": [ - "string", - "null" - ], - "description": "Query key used for alert condition (null for standard schedules)" - }, - "conditionType": { - "type": [ - "string", - "null" - ], - "description": "Alert condition type: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" - }, - "createdAt": { - "type": "string", - "format": "date-time", - "description": "Creation timestamp" - }, - "destinations": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchedulesGetDestination" - }, - "description": "Delivery destination configurations" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Timestamp when the schedule was paused (null if active)" - }, - "entityId": { - "type": "string", - "description": "ID of the associated dashboard" - }, - "fanOut": { - "type": "boolean", - "description": "Whether personalized fan-out delivery is enabled", - "example": false - }, - "filterConfig": { - "description": "The effective dashboard filter configuration that the schedule will run with: the dashboard's current default filters merged under the schedule's persisted overrides, with any keys no longer present on the dashboard dropped. This matches what is shown when the schedule is opened in the Edit Delivery panel, and may differ from the schedule's persisted filter configuration." - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Schedule UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "killJobsOnFailure": { - "type": "boolean", - "description": "Whether to stop the job if any queries fail", - "example": false - }, - "metadata": { - "description": "Schedule metadata including format options and delivery settings. Includes `timezoneOverride` (IANA timezone applied to query execution at render time, or null when no override is set)." - }, - "name": { - "type": "string", - "description": "Schedule name", - "example": "Weekly Sales Report" - }, - "organizationId": { - "type": "string", - "format": "uuid", - "description": "Organization UUID" - }, - "owner": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Schedule owner name" - } - }, - "required": [ - "name" - ] - }, - "ownerId": { - "type": "string", - "format": "uuid", - "description": "User ID of the schedule owner" - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", - "example": "0 9 ? * MON *" - }, - "systemDisabledAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Timestamp when the system disabled the schedule" - }, - "systemDisabledReason": { - "type": [ - "string", - "null" - ], - "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for the schedule", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "format": "date-time", - "description": "Last update timestamp" - } - }, - "required": [ - "conditionQueryMapKey", - "conditionType", - "createdAt", - "destinations", - "disabledAt", - "entityId", - "fanOut", - "id", - "killJobsOnFailure", - "name", - "organizationId", - "owner", - "ownerId", - "schedule", - "systemDisabledAt", - "systemDisabledReason", - "timezone", - "updatedAt" - ] - }, - "SchedulesGetDestination": { - "type": "object", - "properties": { - "format": { - "type": "string", - "description": "Output format: pdf, png, csv, xlsx, json, link_only", - "example": "pdf" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Destination UUID" - }, - "lastCompletedAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Timestamp of last completed delivery" - }, - "lastStatus": { - "type": [ - "string", - "null" - ], - "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" - }, - "metadata": { - "description": "Destination-specific configuration (type, recipients, credentials, etc.)" - }, - "recipients": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchedulesGetRecipient" - }, - "description": "Individual email recipients" - }, - "userGroupRecipients": { - "type": "array", - "items": {}, - "description": "User group recipients" - } - }, - "required": [ - "format", - "id", - "lastCompletedAt", - "lastStatus", - "recipients", - "userGroupRecipients" - ] - }, - "SchedulesGetRecipient": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Recipient ID" - }, - "membership": { - "type": "object", - "properties": { - "user": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Recipient email" - }, - "name": { - "type": [ - "string", - "null" - ], - "description": "Recipient name" - } - }, - "required": [ - "email", - "name" - ] - } - }, - "required": [ - "user" - ] - }, - "membershipId": { - "type": "string", - "format": "uuid", - "description": "Membership ID" - } - }, - "required": [ - "id", - "membership", - "membershipId" - ] - }, - "SchedulesRecipientsGetResponse": { - "type": "object", - "properties": { - "recipients": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EmailRecipient" - }, - "description": "List of individual recipients (for email destinations)." - }, - "type": { - "type": "string", - "enum": [ - "email", - "google_sheets", - "s3", - "sftp", - "slack", - "webhook" - ], - "description": "The schedule's destination type.", - "example": "email" - }, - "userGroupRecipients": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserGroupRecipient" - }, - "description": "List of user group recipients (for email destinations)." - } - }, - "required": [ - "type" - ] - }, - "EmailRecipient": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Recipient's email address.", - "example": "user@example.com" - }, - "id": { - "type": "string", - "description": "Unique identifier for the recipient." - }, - "name": { - "type": "string", - "description": "Recipient's display name.", - "example": "John Doe" - } - }, - "required": [ - "email", - "id", - "name" - ] - }, - "UserGroupRecipient": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "User group ID." - }, - "name": { - "type": "string", - "description": "User group name.", - "example": "Sales Team" - }, - "recipients": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EmailRecipient" - }, - "description": "List of recipients in the user group." - } - }, - "required": [ - "id", - "name", - "recipients" - ] - }, - "SchedulesAddRecipientsResponse": { - "type": "object", - "properties": { - "addedGroupRecipientsCount": { - "type": "number", - "description": "Number of user group recipients added.", - "example": 1 - }, - "addedRecipientsCount": { - "type": "number", - "description": "Number of individual recipients added.", - "example": 2 - }, - "success": { - "type": "boolean", - "description": "Whether the operation was successful.", - "example": true - } - }, - "required": [ - "addedGroupRecipientsCount", - "addedRecipientsCount", - "success" - ] - }, - "SchedulesAddRecipientsBody": { - "type": "object", - "properties": { - "emails": { - "type": "array", - "items": { - "type": "string", - "format": "email" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of email addresses to add as recipients.", - "example": [ - "user@example.com" - ] - }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to add as recipients.", - "example": [ - "123e4567-e89b-12d3-a456-426614174000" - ] - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of user UUIDs to add as recipients. Use the List users and List embed users endpoints to retrieve user IDs.", - "example": [ - "987fcdeb-51a2-43d7-9b56-254415f67890" - ] - } - } - }, - "SchedulesRemoveRecipientsResponse": { - "type": "object", - "properties": { - "removedGroupRecipientsCount": { - "type": "number", - "description": "Number of user group recipients removed.", - "example": 1 - }, - "removedRecipientsCount": { - "type": "number", - "description": "Number of individual recipients removed.", - "example": 2 - }, - "success": { - "type": "boolean", - "description": "Whether the operation was successful.", - "example": true - } - }, - "required": [ - "removedGroupRecipientsCount", - "removedRecipientsCount", - "success" - ] - }, - "SchedulesRemoveRecipientsBody": { - "type": "object", - "properties": { - "emails": { - "type": "array", - "items": { - "type": "string", - "format": "email" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of recipient email addresses to remove from the scheduled task.", - "example": [ - "user@example.com" - ] - }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to remove as recipients.", - "example": [ - "123e4567-e89b-12d3-a456-426614174000" - ] - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of recipient user UUIDs to remove from the scheduled task. Use the List users and List embed users endpoints to retrieve user IDs.", - "example": [ - "987fcdeb-51a2-43d7-9b56-254415f67890" - ] - } - } - }, - "SchedulesTransferOwnershipBody": { - "type": "object", - "properties": { - "userId": { - "type": "string", - "format": "uuid", - "description": "The UUID of the user to transfer schedule ownership to. Use the List users endpoint to retrieve user IDs. The new owner must be a member of the same organization, not be the current owner, and have permission to view the dashboard associated with the schedule.", - "example": "987fcdeb-51a2-43d7-9b56-254415f67890" - } - }, - "required": [ - "userId" - ] - }, - "ScimUsersListResponse": { - "type": "object", - "properties": { - "Resources": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ScimUserResponse" - }, - "description": "List of SCIM users" - }, - "itemsPerPage": { - "type": "number", - "description": "Items per page" - }, - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "SCIM schema URIs" - }, - "startIndex": { - "type": "number", - "description": "Start index (1-based)" - }, - "totalResults": { - "type": "number", - "description": "Total number of results" - } - }, - "required": [ - "Resources", - "itemsPerPage", - "schemas", - "startIndex", - "totalResults" - ] - }, - "ScimUserResponse": { - "type": "object", - "properties": { - "active": { - "type": "boolean", - "description": "Whether the user is active" - }, - "displayName": { - "type": "string", - "description": "Display name" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "SCIM user ID" - }, - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "SCIM schema URIs" - }, - "userName": { - "type": "string", - "format": "email", - "description": "Username (email)" - } - }, - "required": [ - "active", - "displayName", - "id", - "schemas", - "userName" - ] - }, - "ScimUserCreateRequest": { - "type": "object", - "properties": { - "displayName": { - "type": "string", - "description": "Display name of the user", - "example": "John Doe" - }, - "urn:omni:params:1.0:UserAttribute": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - }, - "description": "Omni user attributes" - }, - "userName": { - "type": "string", - "format": "email", - "description": "Email address (username) of the user", - "example": "user@example.com" - } - }, - "required": [ - "displayName", - "userName" - ] - }, - "ScimUserPutRequest": { - "type": "object", - "properties": { - "active": { - "type": "boolean", - "default": true, - "description": "Whether the user is active" - }, - "displayName": { - "type": "string", - "description": "Display name of the user" - }, - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - }, - "description": "Enterprise SCIM user attributes" - }, - "urn:omni:params:1.0:UserAttribute": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - }, - "description": "Omni user attributes" - }, - "userName": { - "type": "string", - "format": "email", - "description": "Email address (username) of the user", - "example": "user@example.com" - } - }, - "required": [ - "userName" - ] - }, - "ScimUserPatchRequest": { - "type": "object", - "properties": { - "Operations": { - "type": "array", - "items": { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "replace", - "Replace", - "add", - "Add", - "Remove", - "remove" - ] - }, - "path": { - "type": "string" - }, - "value": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - } - }, - "urn:omni:params:1.0:UserAttribute": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - } - }, - "active": { - "type": "boolean" - }, - "displayName": { - "type": "string" - }, - "userName": { - "type": "string", - "format": "email" - } - } - } - ] - } - }, - "required": [ - "op", - "value" - ] - }, - "minItems": 1, - "description": "List of patch operations to apply" - }, - "schemas": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "urn:ietf:params:scim:api:messages:2.0:PatchOp" - ] - }, - "description": "SCIM schema URIs" - } - }, - "required": [ - "Operations", - "schemas" - ] - }, - "ScimGroupsListResponse": { - "type": "object", - "properties": { - "Resources": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ScimGroupResponse" - }, - "description": "List of SCIM groups" - }, - "itemsPerPage": { - "type": "number", - "description": "Items per page" - }, - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "SCIM schema URIs" - }, - "startIndex": { - "type": "number", - "description": "Start index (1-based)" - }, - "totalResults": { - "type": "number", - "description": "Total number of results" - } - }, - "required": [ - "Resources", - "itemsPerPage", - "schemas", - "startIndex", - "totalResults" - ] - }, - "ScimGroupResponse": { - "type": "object", - "properties": { - "displayName": { - "type": "string", - "description": "Group display name" - }, - "id": { - "type": "string", - "description": "SCIM group ID (miniUuid)" - }, - "members": { - "type": "array", - "items": { - "type": "object", - "properties": { - "display": { - "type": "string", - "description": "Member display name" - }, - "value": { - "type": "string", - "format": "uuid", - "description": "Member user ID" - } - }, - "required": [ - "display", - "value" - ] - }, - "description": "Group members" - }, - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "SCIM schema URIs" - } - }, - "required": [ - "displayName", - "id", - "schemas" - ] - }, - "ScimGroupsCreateBody": { - "type": "object", - "properties": { - "displayName": { - "type": "string", - "description": "Display name of the group", - "example": "Engineering Team" - }, - "members": { - "type": "array", - "items": { - "type": "object", - "properties": { - "value": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "value" - ] - }, - "default": [], - "description": "List of group members" - } - }, - "required": [ - "displayName" - ] - }, - "ScimGroupsReplaceBody": { - "type": "object", - "properties": { - "displayName": { - "type": "string", - "description": "Display name of the group", - "example": "Engineering Team" - }, - "members": { - "type": "array", - "items": { - "type": "object", - "properties": { - "display": { - "type": "string", - "description": "Display name of the member", - "example": "john.doe@example.com" - }, - "value": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "display", - "value" - ] - }, - "description": "List of group members" - } - }, - "required": [ - "displayName", - "members" - ] - }, - "ScimGroupsPatchBody": { - "type": "object", - "properties": { - "Operations": { - "type": "array", - "items": { - "anyOf": [ - { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "replace", - "Replace" - ], - "description": "Operation type", - "example": "replace" - }, - "value": { - "type": "object", - "properties": { - "displayName": { - "type": "string", - "description": "New display name", - "example": "Engineering Team" - }, - "id": { - "type": "string", - "description": "Group ID" - } - }, - "required": [ - "displayName" - ] - } - }, - "required": [ - "op", - "value" - ] - }, - { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "remove", - "Remove" - ], - "description": "Operation type", - "example": "remove" - }, - "path": { - "type": "string", - "pattern": "members\\[value eq \"(.{36})\"\\]", - "description": "SCIM path for member to remove", - "example": "members[value eq \"550e8400-e29b-41d4-a716-446655440000\"]" - } - }, - "required": [ - "op", - "path" - ] - }, - { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "add", - "Add" - ], - "description": "Operation type", - "example": "add" - }, - "path": { - "type": "string", - "enum": [ - "members" - ], - "description": "Path for members", - "example": "members" - }, - "value": { - "type": "array", - "items": { - "type": "object", - "properties": { - "display": { - "type": "string", - "description": "Display name of the member", - "example": "john.doe@example.com" - }, - "value": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "value" - ] - } - } - }, - "required": [ - "op", - "path", - "value" - ] - }, - { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "replace", - "Replace" - ], - "description": "Operation type", - "example": "replace" - }, - "path": { - "type": "string", - "enum": [ - "members", - "displayName" - ], - "description": "Path for attribute to replace", - "example": "members" - }, - "value": { - "anyOf": [ - { - "type": "array", - "items": { - "type": "object", - "properties": { - "display": { - "type": "string", - "description": "Display name of the member", - "example": "john.doe@example.com" - }, - "value": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "value" - ] - } - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "op", - "path", - "value" - ] - } - ] - }, - "description": "List of SCIM patch operations" - }, - "schemas": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "urn:ietf:params:scim:api:messages:2.0:PatchOp" - ] - }, - "description": "SCIM schema URIs" - } - }, - "required": [ - "Operations", - "schemas" - ] - }, - "DocumentExportResponse": { - "type": "object", - "properties": { - "dashboard": { - "description": "Dashboard configuration and layout" - }, - "document": { - "type": "object", - "properties": { - "ephemeral": { - "type": "string" - }, - "name": { - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "exportVersion": { - "type": "string" - }, - "fileUploads": { - "type": "object", - "additionalProperties": {} - }, - "queryModels": { - "type": "object", - "additionalProperties": {} - }, - "workbookModel": {} - }, - "required": [ - "document", - "exportVersion", - "queryModels" - ] - }, - "DocumentImportResponse": { - "type": "object", - "properties": { - "documentId": { - "type": "string", - "format": "uuid", - "description": "ID of the imported document" - }, - "identifier": { - "type": "string", - "description": "Document identifier (miniUuid)" - } - }, - "required": [ - "documentId", - "identifier" - ] - }, - "DocumentImportBody": { - "type": "object", - "properties": { - "baseModelId": { - "type": "string", - "format": "uuid", - "description": "Base model ID for the imported document" - }, - "dashboard": { - "description": "Dashboard export data" - }, - "document": { - "type": "object", - "properties": { - "ephemeral": { - "type": "string" - }, - "name": { - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "exportVersion": { - "type": "string", - "enum": [ - "0.1" - ] - }, - "fileUploads": { - "type": "object", - "additionalProperties": {} - }, - "folderPath": { - "type": "string" - }, - "identifier": { - "type": "string" - }, - "queryModels": { - "type": "object", - "additionalProperties": {} - }, - "workbookModel": {} - }, - "required": [ - "baseModelId", - "document", - "exportVersion", - "queryModels" - ] - }, - "UserAttributesListResponse": { - "type": "object", - "properties": { - "records": { - "type": "array", - "items": { - "type": "object", - "properties": { - "default_value": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - } - }, - { - "type": "null" - } - ], - "description": "Default value applied when no user-specific value is set. When multiple_values is true, this is an array. Null if no default is configured.", - "example": "us-east" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Human-readable description of the attribute and its purpose", - "example": "User region for row-level security filtering" - }, - "id": { - "type": "string", - "description": "Unique identifier for custom attributes. Empty string for system-defined attributes.", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "label": { - "type": "string", - "description": "Display name shown in the Omni UI", - "example": "Region" - }, - "multiple_values": { - "type": "boolean", - "description": "Whether the attribute accepts an array of values. When true, default_value and user-specific values are arrays.", - "example": false - }, - "name": { - "type": "string", - "description": "Reference name used in model SQL and in embed SSO URL parameters", - "example": "region" - }, - "system": { - "type": "boolean", - "description": "System-defined attributes (e.g. omni_user_id, omni_user_email) are built-in and read-only. Custom attributes have system=false.", - "example": false - }, - "type": { - "type": "string", - "enum": [ - "String", - "Number" - ], - "description": "Data type that determines valid values. String attributes accept text, Number attributes accept numeric values stored as strings for precision.", - "example": "String" - } - }, - "required": [ - "default_value", - "description", - "id", - "label", - "multiple_values", - "name", - "system", - "type" - ] - }, - "description": "All user attribute definitions in the organization, including both system-defined and custom attributes" - } - }, - "required": [ - "records" - ] - }, - "UploadsListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Upload" - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "Upload": { - "type": "object", - "properties": { - "connection_id": { - "type": "string", - "format": "uuid", - "description": "Connection ID the upload is associated with" - }, - "created_at": { - "type": "string", - "format": "date-time", - "description": "When the file was uploaded" - }, - "file_name": { - "type": "string", - "description": "Original file name", - "example": "users.csv" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the upload" - }, - "in_db_as_table_name": { - "type": [ - "string", - "null" - ], - "description": "Database table name if uploaded to database scratch schema" - }, - "model_id": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Model ID the upload is associated with (inferred from connection's shared model if not explicitly set)" - }, - "size_bytes": { - "type": [ - "number", - "null" - ], - "description": "File size in bytes" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "Last update timestamp" - }, - "uploaded_by_user": { - "type": [ - "object", - "null" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "User ID of the uploader" - }, - "name": { - "type": "string", - "description": "Name of the user who uploaded the file" - } - }, - "required": [ - "id", - "name" - ], - "description": "User who uploaded the file" - }, - "view_name": { - "type": "string", - "description": "View name associated with the upload" - } - }, - "required": [ - "connection_id", - "created_at", - "file_name", - "id", - "in_db_as_table_name", - "model_id", - "size_bytes", - "updated_at", - "uploaded_by_user", - "view_name" - ] - }, - "UploadCreateResponse": { - "type": "object", - "properties": { - "fileName": { - "type": "string", - "description": "Original file name", - "example": "users.csv" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the upload" - }, - "inDbAsTableName": { - "type": "string", - "description": "Database table name in the scratch schema" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model ID the view was created in" - }, - "rowCount": { - "type": "integer", - "description": "Number of rows in the uploaded file" - }, - "truncated": { - "type": "boolean", - "description": "Whether the file was truncated due to row limit" - }, - "viewCreated": { - "type": "boolean", - "description": "Whether a view was created in the model" - }, - "viewName": { - "type": "string", - "description": "Name of the view created" - } - }, - "required": [ - "fileName", - "id", - "inDbAsTableName", - "modelId", - "rowCount", - "truncated", - "viewCreated", - "viewName" - ] - }, - "UploadCreateBody": { - "type": "object", - "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "UUID of the branch to create the view in (mutually exclusive with branchName)" - }, - "branchName": { - "type": "string", - "description": "Name of the branch to create the view in (mutually exclusive with branchId)" - }, - "file": { - "type": "string", - "description": "The CSV file to upload", - "format": "binary" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "UUID of the model to create the view in" - }, - "viewName": { - "type": "string", - "description": "Override the view name (defaults to sanitized file name)" - } - }, - "required": [ - "file", - "modelId" - ] - }, - "UploadDeleteResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the deletion was successful" - } - }, - "required": [ - "success" - ] - }, - "UsersGetModelRolesResponse": { - "type": "object", - "properties": { - "membershipId": { - "type": "string", - "format": "uuid", - "description": "The user membership ID" - }, - "results": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RoleAssignmentResult" - }, - "description": "List of role assignments" - } - }, - "required": [ - "membershipId", - "results" - ] - }, - "RoleAssignmentResult": { - "type": "object", - "properties": { - "baseRole": { - "type": "string", - "description": "The base role definition name", - "example": "VIEWER" - }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection this role applies to" - }, - "from": { - "$ref": "#/components/schemas/RoleOrigin" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model this role applies to" - }, - "priority": { - "type": "number", - "description": "Priority for role resolution (higher = more permissive)" - }, - "resolved": { - "type": "boolean", - "description": "Whether this is the resolved (effective) role" - }, - "roleName": { - "type": "string", - "description": "The role name (base or custom)", - "example": "VIEWER" - } - }, - "required": [ - "baseRole", - "connectionId", - "from", - "modelId", - "priority", - "resolved", - "roleName" - ] - }, - "RoleOrigin": { - "oneOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "USER" - ], - "description": "Role assigned directly to user" - } - }, - "required": [ - "type" - ] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "ORG" - ], - "description": "Role inherited from organization" - } - }, - "required": [ - "type" - ] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "BASE" - ], - "description": "Connection base role" - } - }, - "required": [ - "type" - ] - }, - { - "type": "object", - "properties": { - "depth": { - "type": "number", - "description": "Nesting depth of the group" - }, - "miniUuid": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "name": { - "type": "string", - "description": "Name of the group", - "example": "Engineering Team" - }, - "type": { - "type": "string", - "enum": [ - "GROUP" - ], - "description": "Role inherited from group membership" - } - }, - "required": [ - "depth", - "miniUuid", - "name", - "type" - ] - } - ], - "description": "Origin of this role assignment" - }, - "UsersAssignModelRoleResponse": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "The connection ID for this role assignment" - }, - "membershipId": { - "type": "string", - "format": "uuid", - "description": "The user membership ID" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The model ID for this role assignment" - }, - "roleName": { - "type": "string", - "description": "The assigned role name", - "example": "VIEWER" - } - }, - "required": [ - "connectionId", - "membershipId", - "modelId", - "roleName" - ] - }, - "UsersAssignModelRoleBody": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model ID for model-level role assignment. Required if connectionId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "roleName": { - "type": "string", - "minLength": 1, - "description": "Name of the role to assign (base or custom role)", - "example": "VIEWER" - } - }, - "required": [ - "roleName" - ] - }, - "UsersListEmailOnlyResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "type": "object", - "properties": { - "email": { - "type": "string", - "description": "User email address", - "example": "user@example.com" - }, - "user_attributes": { - "type": "object", - "additionalProperties": {}, - "description": "User attributes as key-value pairs" - }, - "user_id": { - "type": "string", - "format": "uuid", - "description": "User ID" - } - }, - "required": [ - "email", - "user_attributes", - "user_id" - ] - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "UsersCreateEmailOnlyResponse": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address of the created user", - "example": "user@example.com" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "ID of the created user" - } - }, - "required": [ - "email", - "userId" - ] - }, - "UsersCreateEmailOnlyBody": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address for the user", - "example": "user@example.com" - }, - "userAttributes": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "description": "Optional user attributes as key-value pairs" - } - }, - "required": [ - "email" - ] - }, - "UsersCreateEmailOnlyBulkResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address of the created user", - "example": "user@example.com" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "ID of the created user" - } - }, - "required": [ - "email", - "userId" - ] - }, - "description": "Results for each created user" - } - }, - "required": [ - "results" - ] - }, - "UsersCreateEmailOnlyBulkBody": { - "type": "object", - "properties": { - "users": { - "type": "array", - "items": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address for the user", - "example": "user@example.com" - }, - "userAttributes": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "description": "Optional user attributes as key-value pairs" - } - }, - "required": [ - "email" - ] - }, - "minItems": 1, - "maxItems": 20, - "description": "Array of users to create (1-20 users)" - } - }, - "required": [ - "users" - ] - }, - "UserGroupsGetModelRolesResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserGroupRoleAssignmentResult" - }, - "description": "List of role assignments" - }, - "userGroupId": { - "type": "string", - "description": "The user group short identifier", - "example": "abc123" - } - }, - "required": [ - "results", - "userGroupId" - ] - }, - "UserGroupRoleAssignmentResult": { - "type": "object", - "properties": { - "baseRole": { - "type": "string", - "description": "The base role definition name", - "example": "VIEWER" - }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection this role applies to" - }, - "from": { - "$ref": "#/components/schemas/UserGroupRoleOrigin" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model this role applies to" - }, - "priority": { - "type": "number", - "description": "Priority for role resolution (higher = more permissive)" - }, - "roleName": { - "type": "string", - "description": "The role name (base or custom)", - "example": "VIEWER" - } - }, - "required": [ - "baseRole", - "connectionId", - "from", - "modelId", - "priority", - "roleName" - ] - }, - "UserGroupRoleOrigin": { - "type": "object", - "properties": { - "depth": { - "type": "number", - "description": "Nesting depth of the group (0 for direct assignment)" - }, - "miniUuid": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "name": { - "type": "string", - "description": "Name of the group", - "example": "Engineering Team" - }, - "type": { - "type": "string", - "enum": [ - "GROUP" - ], - "description": "Role assigned to group" - } - }, - "required": [ - "depth", - "miniUuid", - "name", - "type" - ], - "description": "Origin of this role assignment" - }, - "UserGroupsAssignModelRoleResponse": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "The connection ID for this role assignment" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The model ID for this role assignment" - }, - "roleName": { - "type": "string", - "description": "The assigned role name", - "example": "VIEWER" - }, - "userGroupId": { - "type": "string", - "description": "The user group short identifier", - "example": "abc123" - } - }, - "required": [ - "connectionId", - "modelId", - "roleName", - "userGroupId" - ] - }, - "UserGroupsAssignModelRoleBody": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model ID for model-level role assignment. Required if connectionId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "roleName": { - "type": "string", - "minLength": 1, - "description": "Name of the role to assign (base or custom role)", - "example": "VIEWER" - } - }, - "required": [ - "roleName" - ] - }, - "WhoamiResponse": { - "type": "object", - "properties": { - "keyScope": { - "type": "string", - "enum": [ - "user", - "organization" - ], - "description": "Scope of the API key in use. A separate axis from role: a user-scoped key (PAT/OAuth) acts as a single user and cannot use SCIM, regardless of the user's org role." - }, - "orgRole": { - "type": "string", - "enum": [ - "MEMBER", - "ORG_ADMIN" - ], - "description": "The caller's organization role.", - "example": "MEMBER" - }, - "rolesByModel": { - "type": "object", - "additionalProperties": { - "$ref": "#/components/schemas/WhoamiModelRole" - }, - "description": "Resolved role and effective permissions per model, keyed by model id. Connection role resolves per shared model, so this is per-model rather than a single global role." - }, - "rolesByModelTruncated": { - "type": "boolean", - "description": "Present and `true` when `rolesByModel` was truncated because the caller can access more models than the unfiltered limit. Pass a `modelId` filter to retrieve specific models." - }, - "user": { - "$ref": "#/components/schemas/WhoamiUser" - } - }, - "required": [ - "keyScope", - "orgRole", - "rolesByModel", - "user" - ] - }, - "WhoamiModelRole": { - "type": "object", - "properties": { - "baseRole": { - "type": "string", - "description": "The resolved base role (for custom roles, the base role they extend).", - "example": "QUERIER" - }, - "connectionId": { - "type": "string", - "description": "The connection this model belongs to" - }, - "permissions": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "QUERY_FULL_MODEL", - "QUERY_SQL", - "VIEW_SQL", - "QUERY_TOPICS", - "RUN_CONTENT_QUERIES", - "DOWNLOAD_CONTENT_QUERY", - "UPLOAD_CSV", - "SCHEDULE", - "SAVE_SPREADSHEETS", - "USE_AI", - "USE_IDE", - "USE_WORKBOOKS", - "UPDATE", - "UPDATE_RESTRICTED" - ] - }, - "description": "The caller's resolved/effective permissions on this model, reflecting custom roles. This is a capability signal for the directly-roleable model kinds (schema / shared / extension). It does not enumerate the permissions you derive on branch, workbook, and query models from your role on the base model they descend from \u2014 absence here does not mean you lack access on those derived models. MANAGE_MODEL, READ, and REFRESH_SCHEMA are also not reported: they derive from connection / sibling-model roles rather than a per-model rule.", - "example": [ - "QUERY_TOPICS", - "QUERY_SQL", - "USE_WORKBOOKS" - ] - }, - "roleName": { - "type": "string", - "description": "The resolved role name (informational; may be a custom role). Use `permissions` to decide capability.", - "example": "QUERIER" - } - }, - "required": [ - "baseRole", - "connectionId", - "permissions", - "roleName" - ] - }, - "WhoamiUser": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "The caller's user id" - }, - "membershipId": { - "type": "string", - "description": "The caller's own membership id within this organization. This is the id accepted by the admin `GET /api/v1/users/{id}/model-roles` endpoint (it is distinct from the user id)." - } - }, - "required": [ - "id", - "membershipId" - ] - } - }, - "parameters": {} - }, - "paths": { - "/api/v1/ai/generate-query": { - "post": { - "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model.", - "operationId": "aiGenerateQuery", - "summary": "Generate query from natural language", - "tags": [ - "AI" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiGenerateQueryBody" - } - } - } - }, - "responses": { - "200": { - "description": "Query generated successfully. If runQuery is true (default), includes execution results. Check the error field \u2014 a 200 response may still contain a partial error if the query was generated but execution failed. When the organization is over its AI downgrade threshold the response also carries `downgradedModelTier` naming the cheaper tier the query was generated with.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiGenerateQueryResponse" - } - } - } - }, - "400": { - "description": "Invalid request. The prompt may be missing, the modelId may be invalid, or the AI was unable to generate a query for the given prompt.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "402": { - "description": "AI is unavailable because the organization is over its AI credit limit. The body carries the stable reason code `shutoff`.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiCreditShutoffError" - } - } - } - }, - "403": { - "description": "Insufficient permissions. Requires the querier role on the target model and AI query generation must be enabled for the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "The specified model or topic was not found in the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - }, - "500": { - "description": "AI service error." - } - } - } - }, - "/api/v1/ai/pick-topic": { - "post": { - "description": "Analyze a natural language prompt and determine which topic in the model is the best fit for answering the question. Useful as a preprocessing step before calling generate-query or submitting an AI job, especially when the user's question could relate to multiple topics.", - "operationId": "aiPickTopic", - "summary": "Pick the best topic for a prompt", - "tags": [ - "AI" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiPickTopicBody" - } - } - } - }, - "responses": { - "200": { - "description": "Topic selected successfully. The returned topicId can be used as the topicName parameter in other AI endpoints.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiPickTopicResponse" - } - } - } - }, - "400": { - "description": "Invalid request body. The prompt or modelId may be missing or malformed.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions. Requires the querier role on the target model and AI must be enabled for the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "The specified model was not found, or no accessible topics exist in the model.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - }, - "500": { - "description": "AI service error." - } - } - } - }, - "/api/v1/ai/search-omni-docs": { - "post": { - "description": "Search the Omni documentation using AI to answer questions about Omni features, configuration, modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer with source links to the relevant documentation pages.", - "operationId": "aiSearchOmniDocs", - "summary": "Search Omni documentation", - "tags": [ - "AI" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiSearchOmniDocsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Documentation search completed successfully. Returns a synthesized answer with source links.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiSearchOmniDocsResponse" - } - } - } - }, - "400": { - "description": "Invalid request. The question may be missing or exceed the 2000 character limit.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Omni Agent is not enabled for this organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "500": { - "description": "AI service error." - } - } - } - }, - "/api/v1/ai/jobs": { - "post": { - "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15\u201360 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId.", - "operationId": "aiJobSubmit", - "summary": "Submit an AI job", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobSubmitBody" - } - } - } - }, - "responses": { - "201": { - "description": "Job created and queued for execution. Use the returned jobId to poll for status or retrieve results.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobSubmitResponse" - } - } - } - }, - "400": { - "description": "Invalid request body. Common causes: missing or empty prompt, invalid UUID for modelId/branchId/conversationId, invalid webhook URL format.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions. The AI jobs API must be enabled for the organization, AI query generation must be enabled, and the user must have appropriate model access. User-scoped API keys cannot act on behalf of other users.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "The specified model was not found in the organization, the branchId does not belong to the specified model, or the topicName does not exist in the model (or is excluded by ai_chat_topics restrictions).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - }, - "409": { - "description": "An active job already exists for the specified conversationId. Wait for the current job to complete before submitting another job to the same conversation.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError409" - } - } - } - } - } - } - }, - "/api/v1/ai/jobs/{jobId}": { - "get": { - "description": "Get the current status of an AI job, including its state, progress information, and result summary. The response fields vary by state \u2014 for example, progress is only present during EXECUTING, and resultSummary is only present when COMPLETE. Poll this endpoint every 2\u20135 seconds until the job reaches a terminal state (COMPLETE, FAILED, or CANCELLED).", - "operationId": "aiJobStatus", - "summary": "Get AI job status", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Job status retrieved successfully. Check the state field to determine if the job is still running or has reached a terminal state.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobStatusResponse" - } - } - } - }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions. AI query generation must be enabled for the organization and the caller must have permission to use AI on the job's model.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "Job not found. The job may not exist or may belong to a different organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - } - } - } - }, - "/api/v1/ai/jobs/{jobId}/cancel": { - "post": { - "description": "Request cancellation of an AI job. This endpoint is idempotent \u2014 calling it on an already-cancelled or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING state cannot be cancelled as they are already finalizing results. Only the job owner or organization admins can cancel jobs.", - "operationId": "aiJobCancel", - "summary": "Cancel an AI job", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Cancellation request processed. The state field indicates the job's state after the attempt \u2014 CANCELLED if successful, or the current terminal state if the job had already completed.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobCancelResponse" - } - } - } - }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Permission denied. Only the job owner or organization admins can cancel jobs.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "Job not found. The job may not exist or may belong to a different organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - }, - "409": { - "description": "Concurrent modification conflict. The job state was changed by another request. Retry the cancellation.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError409" - } - } - } - } - } - } - }, - "/api/v1/ai/jobs/{jobId}/result": { - "get": { - "description": "Retrieve the full result of a completed AI job, including all actions taken by the AI (queries generated, data retrieved) and the final summarized answer. Results are only available for jobs in COMPLETE state and are retained for 14 days after completion. The response is streamed directly from storage.", - "operationId": "aiJobResult", - "summary": "Get AI job result", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Full job result including the AI's actions, query results (with CSV data), and the final Markdown-formatted answer.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobResultResponse" - } - } - } - }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions. AI query generation must be enabled for the organization and the caller must have permission to use AI on the job's model.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "Job not found, not in COMPLETE state, or result is no longer available (results are retained for 14 days).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - } - } - } - }, - "/api/v1/ai/jobs/{jobId}/vis": { - "get": { - "description": "Render the visualization from a completed AI job as a PNG image. The endpoint extracts the visualization configuration from the job result, loads Arrow IPC data, and renders it server-side using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back through previous jobs in the conversation to find the original query data.", - "operationId": "aiJobVisualization", - "summary": "Render AI job visualization", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Visualization rendered as a PNG image. The Content-Type header is image/png.", - "content": { - "image/png": { - "schema": { - "format": "binary", - "type": "string" - } - } - } - }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions. AI query generation must be enabled for the organization and the caller must have permission to use AI on the job's model.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "Job not found, not in COMPLETE state, or the apiAiVis feature flag is not enabled.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - }, - "422": { - "description": "The job completed but cannot be rendered as a visualization. Common causes: no visualization action in the job result, no Arrow IPC data available, missing summary fields, or the chart type is not renderable as an image (e.g., tables, KPIs).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError422" - } - } - } - } - } - } - }, - "/api/v1/ai/branding": { - "get": { - "description": "Returns the organization's AI helper branding \u2014 display name, optional custom logo URL, and copy used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's defaults when the organization hasn't configured custom branding, so the response is always populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity.", - "operationId": "aiBranding", - "summary": "Get AI helper branding", - "tags": [ - "AI" - ], - "responses": { - "200": { - "description": "AI branding retrieved successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiBrandingResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "AI access is required to view AI helper branding (no model in the org grants USE_AI to the caller).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - } - } - } - }, - "/api/v1/ai/conversations": { - "get": { - "description": "List the user's recent AI conversations, ordered by most-recent activity. Each record includes the conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to continue the thread), an optional name, and a one-line summary of the most recent prompt for display. Paginated via opaque `pageInfo.nextCursor` \u2014 pass it back as `cursor` to fetch the next page.", - "operationId": "aiConversationsList", - "summary": "List AI conversations", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Paginated list of conversations.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiConversationsListResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - } - } - } - }, - "/api/v1/ai/conversations/{conversationId}": { - "get": { - "description": "Return a conversation with its full message history (alternating user / assistant turns). Used by clients (iOS app, embed widgets) to restore a prior conversation in their UI.", - "operationId": "aiConversationDetail", - "summary": "Get AI conversation with messages", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid" - }, - "required": true, - "name": "conversationId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Conversation with messages in chronological order.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiConversationDetailResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "AI access is required to view chat conversations (no model in the org grants USE_AI to the caller).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "Conversation not found. User-scoped keys also get 404 (not 403) when the conversation exists but belongs to a different user \u2014 existence of another user's conversations is not disclosed.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - } - } - } - }, - "/api/v1/ai/credit-controls": { - "get": { - "description": "Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per-user credit limit, plus read-only context (the credit limit, usage so far this billing period, and the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same AI-admin permission.", - "operationId": "aiCreditControlsGet", - "summary": "Get AI credit controls", - "tags": [ - "AI" - ], - "responses": { - "200": { - "description": "Current credit controls. Thresholds are `null` when the corresponding control is off.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiCreditControlsResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions, or AI credit controls are not enabled for the organization. Requires AI-admin access.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - } - } - }, - "patch": { - "description": "Update the organization's AI credit controls: the downgrade and shutoff thresholds and the default per-user credit limit (userDefaultCredits). All fields are optional and tri-state: omit a field to leave it unchanged, send `null` to turn that control off (for userDefaultCredits: unlimited by default), or send a non-negative number to set it. At least one field is required. The `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the full current state, the same shape as GET.", - "operationId": "aiCreditControlsUpdate", - "summary": "Update AI credit controls", - "tags": [ - "AI" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiCreditControlsUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Thresholds updated. Returns the full current state.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiCreditControlsResponse" - } - } - } - }, - "400": { - "description": "Invalid request. Common causes: empty body, a negative value, an unknown field, or downgradeCredits above shutoffCredits.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions, or AI credit controls are not enabled. Requires AI-admin access.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - } - } - } - }, - "/api/v1/ai/credit-controls/users": { - "get": { - "description": "List the organization's active individual user AI credit limits, ordered by userId ascending. Only users with an individual limit appear \u2014 everyone else follows the org default. A `null` creditLimit is an explicit unlimited override, distinct from following the default. Paginated via opaque cursors: pass `pageInfo.nextCursor` from one response as the `cursor` query parameter on the next request. Requires the same manage-user-attributes permission as the PATCH.", - "operationId": "aiCreditControlsUsersList", - "summary": "List individual users' AI credit limits", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - } - ], - "responses": { - "200": { - "description": "One page of users' individual AI credit limits.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiCreditControlsUsersListResponse" - } - } - } - }, - "400": { - "description": "Invalid cursor or pageSize.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions, or per-user AI credit limits are not enabled for the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - } - } - }, - "patch": { - "description": "Set individual users' AI credit limits in bulk. Each entry names a user (`userId`) and either sets an individual limit (`creditLimit`: a non-negative number, or `null` for unlimited) or removes one (`useDefaultLimit: true`) so the user follows the org default. Each userId may appear at most once and must be a member of the organization. All updates are applied in one transaction, so either every entry takes effect or none do \u2014 an invalid userId fails the whole request with a 404 naming it. Requires the same manage-user-attributes permission as the AI credit limit settings pages.", - "operationId": "aiCreditControlsUsersUpdate", - "summary": "Set individual users' AI credit limits", - "tags": [ - "AI" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiUserCreditLimitsUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "All entries applied. Returns each user's effective limit, in request order.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiUserCreditLimitsResponse" - } - } - } - }, - "400": { - "description": "Invalid request. Common causes: an empty users array, more than 1000 entries, an entry with both creditLimit and useDefaultLimit (or neither), a negative creditLimit, or a duplicated userId.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions, per-user AI credit limits are not enabled, or credit controls editing is disabled for the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "A userId is not a member of the organization; the response names the first invalid id. No limits are changed.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - } - } - } - }, - "/api/v1/ai/routines": { - "get": { - "description": "List routines for the calling user, newest first. Includes routines paused by the owner or disabled by Omni, but excludes deleted routines. Use `pageInfo.nextCursor` from one response as the `cursor` query parameter on the next request. Organization API keys can pass `?userId=` to list routines for a specific organization member.", - "operationId": "routinesList", - "summary": "List routines", - "tags": [ - "AI Routines" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Field to sort results by" - }, - "required": false, - "description": "Field to sort results by", - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Paginated list of routines.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoutinesListResponse" - } - } - } - }, - "400": { - "description": "Invalid pagination cursor or `userId` value.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to list routines for another user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "The `userId` membership was not found in the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - } - } - }, - "post": { - "description": "Create a routine that runs a saved prompt on a schedule and delivers the AI response through a single destination \u2014 email (one or more recipients / user groups) or Slack (a single channel or direct message). Each scheduled run executes once using the routine owner's permissions, and every recipient receives the same result. Organization API keys can pass `?userId=` to create the routine for a specific organization member.", - "operationId": "routineCreate", - "summary": "Create a routine", - "tags": [ - "AI Routines" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoutineCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Routine created successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoutineCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body, recipient configuration, schedule, or timezone. Also returned when the schedule is more frequent than the organization allows.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "AI routines or AI query generation are not enabled for the organization, or the API key cannot act on behalf of the requested user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "Model, branch, or topic not found, or not accessible to the requested user.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - }, - "429": { - "description": "The resolved user already has the maximum number of active routines.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError429" - } - } - } - } - } - } - }, - "/api/v1/ai/routines/{id}": { - "get": { - "description": "Get a single routine, including the status of its most recent completed run.", - "operationId": "routineGet", - "summary": "Get a routine", - "tags": [ - "AI Routines" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the routine." - }, - "required": true, - "description": "The UUID of the routine.", - "name": "id", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Routine details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoutineResponse" - } - } - } - }, - "400": { - "description": "Invalid routine ID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to access another user's routine.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "Routine not found or has been deleted.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - } - } - }, - "patch": { - "description": "Update a routine. All request fields are optional, and only supplied fields are changed. Supplying `destination` replaces the full recipient configuration.", - "operationId": "routineUpdate", - "summary": "Update a routine", - "tags": [ - "AI Routines" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the routine." - }, - "required": true, - "description": "The UUID of the routine.", - "name": "id", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoutineUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Updated routine details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoutineResponse" - } - } - } - }, - "400": { - "description": "Invalid routine ID, request body, recipient configuration, schedule, or timezone.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to update another user's routine.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "Routine not found or has been deleted.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - } - } - }, - "delete": { - "description": "Delete a routine. It stops running immediately and no longer appears in list or get responses.", - "operationId": "routineDelete", - "summary": "Delete a routine", - "tags": [ - "AI Routines" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the routine." - }, - "required": true, - "description": "The UUID of the routine.", - "name": "id", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Routine deleted successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoutineDeleteResponse" - } - } - } - }, - "400": { - "description": "Invalid routine ID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to delete another user's routine.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "Routine not found or has already been deleted.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - } - } - } - }, - "/api/v1/ai/routines/{id}/trigger": { - "post": { - "description": "Run a routine immediately, in addition to its schedule. The run executes once using the routine owner's permissions and delivers the AI response to every configured recipient \u2014 it is not a private preview. Returns once the run has started; the result is delivered asynchronously. Organization API keys can pass `?userId=` to act on behalf of a specific organization member.", - "operationId": "routineTrigger", - "summary": "Run a routine now", - "tags": [ - "AI Routines" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the routine." - }, - "required": true, - "description": "The UUID of the routine.", - "name": "id", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "202": { - "description": "The run has started.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoutineTriggerResponse" - } - } - } - }, - "400": { - "description": "Invalid routine ID, or the routine cannot run as configured (e.g. its model, branch, or owner is no longer accessible).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "AI routines or AI query generation are not enabled for the organization, or a user-scoped API key tried to run another user's routine.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "The routine does not exist or cannot be triggered (deleted, paused, or disabled by Omni).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - }, - "409": { - "description": "A run is already in progress for this routine.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError409" - } - } - } - } - } - } - }, - "/api/v1/api-keys": { - "get": { - "description": "Returns all API tokens in the organization, including organization-level keys, personal access tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions.", - "operationId": "apiKeysList", - "summary": "List API tokens", - "tags": [ - "API Tokens" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Cursor from the previous response (token UUID)" - }, - "required": false, - "description": "Cursor from the previous response (token UUID)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "createdAt", - "name" - ], - "default": "createdAt" - }, - "required": false, - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "organization", - "personal", - "mcp" - ], - "description": "Filter by API token type. When omitted, all types are returned.", - "example": "personal" - }, - "required": false, - "description": "Filter by API token type. When omitted, all types are returned.", - "name": "type", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Paginated list of API tokens", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiKeyListResponse" - } - } - } - }, - "400": { - "description": "Invalid query parameters" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Insufficient permissions" - } - } - } - }, - "/api/v1/api-keys/{id}": { - "get": { - "description": "Returns a single API token by id. Requires organization admin permissions.", - "operationId": "apiKeysGet", - "summary": "Get API token", - "tags": [ - "API Tokens" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "required": true, - "description": "Token UUID", - "name": "id", - "in": "path" - } - ], - "responses": { - "200": { - "description": "The requested API token", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiKey" - } - } - } - }, - "400": { - "description": "Malformed `id` (must be a UUID)" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Insufficient permissions" - }, - "404": { - "description": "Token not found in this organization" - } - } - }, - "put": { - "description": "Enables or disables an API token. Requires organization admin permissions.", - "operationId": "apiKeysUpdate", - "summary": "Enable or disable an API token", - "tags": [ - "API Tokens" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "required": true, - "description": "Token UUID", - "name": "id", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiKeyUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "The updated API token", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiKey" - } - } - } - }, - "400": { - "description": "Invalid body, malformed `id`, or missing/malformed `Authorization` header" - }, - "403": { - "description": "Invalid bearer token, or caller lacks organization admin permissions" - }, - "404": { - "description": "Token not found in this organization" - }, - "405": { - "description": "Method not allowed" - } - } - }, - "delete": { - "description": "Revokes an API token by permanently deleting it. Works for all token types. Requires organization admin permissions.", - "operationId": "apiKeysDelete", - "summary": "Revoke an API token", - "tags": [ - "API Tokens" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "required": true, - "description": "Token UUID", - "name": "id", - "in": "path" - } - ], - "responses": { - "200": { - "description": "The token was revoked", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiKeyDeleteResponse" - } - } - } - }, - "400": { - "description": "Malformed `id`, or missing/malformed `Authorization` header" - }, - "403": { - "description": "Invalid bearer token, or caller lacks organization admin permissions" - }, - "404": { - "description": "Token not found in this organization" - }, - "405": { - "description": "Method not allowed" - } - } - } - }, - "/api/v1/connections": { - "get": { - "operationId": "connectionsList", - "summary": "List connections", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Filter by database name (case-insensitive contains)", - "example": "analytics" - }, - "required": false, - "description": "Filter by database name (case-insensitive contains)", - "name": "database", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by dialect(s). Comma-separated list for multiple values", - "example": "snowflake,bigquery" - }, - "required": false, - "description": "Filter by dialect(s). Comma-separated list for multiple values", - "name": "dialect", - "in": "query" - }, - { - "schema": { - "type": "boolean", - "description": "Include soft-deleted connections in results", - "example": false - }, - "required": false, - "description": "Include soft-deleted connections in results", - "name": "includeDeleted", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by connection name (case-insensitive contains)", - "example": "Production" - }, - "required": false, - "description": "Filter by connection name (case-insensitive contains)", - "name": "name", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "description": "Sort direction", - "example": "desc" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "database", - "dialect", - "name" - ], - "description": "Field to sort by", - "example": "name" - }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of connections", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connections": { - "type": "array", - "items": { - "type": "object", - "properties": { - "allowBranchConnectionEnvironments": { - "type": [ - "boolean", - "null" - ], - "description": "Whether a branch may select its own connection environment. When user-attribute environment selection is also enabled, a branch selection overrides the user attribute.", - "example": false - }, - "baseRole": { - "type": [ - "string", - "null" - ], - "description": "Default role for users on this connection", - "example": "QUERIER" - }, - "branchConnectionEnvironmentOverridesUserAttr": { - "type": [ - "boolean", - "null" - ], - "deprecated": true, - "description": "Deprecated alias for `allowBranchConnectionEnvironments`; same value. Use `allowBranchConnectionEnvironments` instead.", - "example": false - }, - "createdAt": { - "type": "string", - "description": "Timestamp when connection was created (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "database": { - "type": [ - "string", - "null" - ], - "description": "Database name", - "example": "analytics_db" - }, - "defaultSchema": { - "type": [ - "string", - "null" - ], - "description": "Default schema for the connection", - "example": "public" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when connection was deleted (ISO 8601)", - "example": null - }, - "dialect": { - "type": "string", - "enum": [ - "snowflake", - "bigquery", - "redshift", - "postgres", - "mysql", - "mariadb", - "databricks", - "databricks_lakebase", - "trino", - "athena", - "duckdb", - "motherduck", - "sqlserver", - "clickhouse", - "singlestore" - ], - "description": "Database dialect type", - "example": "snowflake" - }, - "environmentConnectionSwitchesSchemaModel": { - "type": [ - "boolean", - "null" - ], - "description": "Whether environment connections switch schema model", - "example": false - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection identifier", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "name": { - "type": "string", - "description": "Connection display name", - "example": "Production Snowflake" - }, - "updatedAt": { - "type": "string", - "description": "Timestamp when connection was last updated (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "userAttributeNameForConnectionEnvironments": { - "type": [ - "string", - "null" - ], - "description": "User attribute name used for connection environments", - "example": "region" - }, - "userAttributeValuesForDefaultEnvironment": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default user attribute values for the base environment", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "allowBranchConnectionEnvironments", - "baseRole", - "branchConnectionEnvironmentOverridesUserAttr", - "createdAt", - "database", - "defaultSchema", - "deletedAt", - "dialect", - "environmentConnectionSwitchesSchemaModel", - "id", - "name", - "updatedAt", - "userAttributeNameForConnectionEnvironments", - "userAttributeValuesForDefaultEnvironment" - ], - "description": "Connection object", - "title": "Connection" - }, - "description": "List of connections" - } - }, - "required": [ - "connections" - ], - "description": "List connections response", - "title": "ConnectionsListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - } - } - }, - "post": { - "description": "Create a new database connection. The request body varies by dialect - see dialect-specific documentation for required fields.", - "operationId": "connectionsCreate", - "summary": "Create connection", - "tags": [ - "Connections" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "acceptsLicense": { - "type": "boolean", - "description": "Acceptance of the license terms. Required for Oracle connections.", - "example": true - }, - "allowsUserSpecificTimezones": { - "type": "boolean", - "default": false, - "description": "Whether to allow users to specify their own timezones", - "example": false - }, - "alwaysScopeViewNames": { - "type": "boolean", - "description": "Whether to always include schema (and catalog) prefixes in generated view names, even for tables in the default schema. Defaults to true for dialects that support multiple catalogs, false otherwise.", - "example": true - }, - "authenticationType": { - "type": "string", - "description": "Authentication type. Applicable for BigQuery, MSSQL, Snowflake, Databricks, and Athena.", - "example": "snowflake-password" - }, - "awsRoleArn": { - "type": "string", - "description": "AWS IAM role ARN. Applicable for Athena only.", - "example": "arn:aws:iam::123456789012:role/OmniAthenaRole" - }, - "baseRole": { - "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "RESTRICTED_QUERIER", - "QUERIER", - "MODELER", - "CONNECTION_ADMIN" - ], - "description": "The default role for users accessing the connection", - "example": "QUERIER" - }, - "database": { - "type": "string", - "description": "The default database/catalog to connect to. For BigQuery, this is the project ID. For Athena, this is the data catalog.", - "example": "analytics_db" - }, - "defaultSchema": { - "type": "string", - "description": "The default schema to use. Required for MSSQL.", - "example": "public" - }, - "dialect": { - "type": "string", - "enum": [ - "athena", - "bigquery", - "clickhouse", - "databricks", - "databricks_lakebase", - "exasol", - "mariadb", - "motherduck", - "mssql", - "mysql", - "oracle", - "postgres", - "redshift", - "sap_hana", - "snowflake", - "starrocks", - "trino" - ], - "description": "The database dialect", - "example": "snowflake" - }, - "enableDbSemanticLayerIntegration": { - "type": "boolean", - "default": false, - "description": "Enable the dialect-native semantic layer integration. Applicable for Snowflake and Databricks.", - "example": false - }, - "enableDbSemanticLayerTopics": { - "type": "boolean", - "default": false, - "description": "Enable the dialect-native semantic layer topics. Applicable for Snowflake and Databricks.", - "example": false - }, - "externalOauthAudience": { - "type": "string", - "description": "External OAuth audience claim. Applicable for Snowflake." - }, - "externalOauthAuthorizationUrl": { - "type": "string", - "format": "uri", - "description": "External OAuth authorization URL (must be HTTPS). Applicable for Snowflake.", - "example": "https://oauth.example.com/authorize" - }, - "externalOauthTokenUrl": { - "type": "string", - "format": "uri", - "description": "External OAuth token URL (must be HTTPS). Applicable for Snowflake.", - "example": "https://oauth.example.com/token" - }, - "host": { - "type": "string", - "description": "The hostname or IP address of the database server. For Snowflake, provide only the account identifier.", - "example": "myaccount" - }, - "hostOverride": { - "type": "string", - "description": "Custom Snowflake host (when not using the account identifier). Mutually exclusive with `host`.", - "example": "myaccount.snowflakecomputing.com" - }, - "includeOtherCatalogs": { - "type": "string", - "description": "Comma-separated list of other catalogs/databases to include. Only applicable for databases that support multi-catalog queries.", - "example": "other_project1,other_project2" - }, - "includeSchemas": { - "type": "string", - "description": "Comma-separated list of schemas to include. Leave empty to include all schemas.", - "example": "public,analytics" - }, - "inferRelationshipsFromColumnNames": { - "type": "boolean", - "default": true, - "description": "Whether to infer relationships from column-name conventions during schema refresh. Defaults to true.", - "example": true - }, - "inferRelationshipsFromForeignKeys": { - "type": "boolean", - "default": false, - "description": "Whether to infer relationships from declared foreign keys during schema refresh. Currently honored for Postgres and Snowflake.", - "example": false - }, - "maxBillingBytes": { - "type": "string", - "description": "Maximum bytes that can be billed for a BigQuery query. Applicable for BigQuery only.", - "example": "1000000000" - }, - "name": { - "type": "string", - "description": "A descriptive name for the connection", - "example": "Production Warehouse" - }, - "oauthClientId": { - "type": "string", - "description": "OAuth client ID for admin schema refresh. Applicable for Snowflake and Databricks." - }, - "oauthClientSecretUnencrypted": { - "type": "string", - "description": "OAuth client secret for admin schema refresh. Applicable for Snowflake and Databricks." - }, - "offloadedSchemas": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ], - "description": "Schemas whose tables should be queried via the offloaded engine. Accepts a comma-separated string or an array of schema names.", - "example": [ - "analytics_archive" - ] - }, - "passwordUnencrypted": { - "type": "string", - "description": "The password to authenticate with. For BigQuery, this must be the JSON service account key file content. For Snowflake with keypair authentication, this can be omitted." - }, - "port": { - "type": "integer", - "description": "The port number for the database connection. Not required for Snowflake, MotherDuck, BigQuery, Databricks, and Athena.", - "example": 5432 - }, - "privateKey": { - "type": "string", - "description": "An RSA key for keypair authentication. Omni will automatically add PEM headers if none are provided. Applicable for Snowflake only." - }, - "queryTimeoutSeconds": { - "type": "integer", - "maximum": 3600, - "description": "The timeout in seconds for queries. Maximum value is 3600 (1 hour). Only applicable for databases that support query timeouts.", - "example": 900 - }, - "queryTimezone": { - "type": "string", - "description": "The timezone to use for queries", - "example": "NONE" - }, - "region": { - "type": "string", - "description": "Required for BigQuery and Athena connections. For BigQuery, specify a region like \"us\". For Athena, specify an AWS region like \"us-east-1\".", - "example": "us-east-1" - }, - "scratchSchema": { - "type": "string", - "description": "Schema to use for data input (upload) tables. If not specified, a suitable default will be chosen.", - "example": "omni_scratch" - }, - "systemTimezone": { - "type": "string", - "description": "The timezone to use for the system", - "example": "UTC" - }, - "trustServerCertificate": { - "type": "boolean", - "default": false, - "description": "Whether to trust the server certificate. Applicable for MSSQL, Exasol, ClickHouse, Trino, and SAP HANA.", - "example": false - }, - "useMachineAuth": { - "type": "boolean", - "description": "Whether to authenticate using machine credentials (OAuth M2M). Applicable for Athena and Databricks.", - "example": false - }, - "username": { - "type": "string", - "description": "The username to authenticate with. For BigQuery, this is the client email from the service account.", - "example": "analytics_user" - }, - "warehouse": { - "type": "string", - "description": "Required for Snowflake (specify the warehouse) and Databricks (specify the HTTP path). May be omitted for Snowflake OAuth connections, in which case each user's Snowflake default warehouse applies.", - "example": "COMPUTE_WH" - }, - "wifAudience": { - "type": "string", - "description": "Full resource name of the workload identity pool provider. Required for BigQuery workload identity federation authentication.", - "example": "//iam.googleapis.com/projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider" - }, - "wifServiceAccountEmail": { - "type": "string", - "description": "Service account to impersonate for BigQuery workload identity federation authentication. When omitted, the federated identity is used directly.", - "example": "omni@my-project.iam.gserviceaccount.com" - } - }, - "required": [ - "dialect", - "name", - "passwordUnencrypted" - ], - "description": "Request body for creating a database connection. Required fields: dialect, name, passwordUnencrypted. Additional fields may be required depending on the dialect.", - "title": "ConnectionsCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Connection created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "data": { - "type": "string", - "format": "uuid", - "description": "Created connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "data", - "success" - ], - "description": "Create connection response", - "title": "ConnectionsCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or dialect" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - } - } - } - }, - "/api/v1/connections/{id}": { - "get": { - "description": "Fetch a single connection by ID.", - "operationId": "connectionsGet", - "summary": "Get connection", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "id", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Connection object", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connection": { - "type": "object", - "properties": { - "allowBranchConnectionEnvironments": { - "type": [ - "boolean", - "null" - ], - "description": "Whether a branch may select its own connection environment. When user-attribute environment selection is also enabled, a branch selection overrides the user attribute.", - "example": false - }, - "baseRole": { - "type": [ - "string", - "null" - ], - "description": "Default role for users on this connection", - "example": "QUERIER" - }, - "branchConnectionEnvironmentOverridesUserAttr": { - "type": [ - "boolean", - "null" - ], - "deprecated": true, - "description": "Deprecated alias for `allowBranchConnectionEnvironments`; same value. Use `allowBranchConnectionEnvironments` instead.", - "example": false - }, - "createdAt": { - "type": "string", - "description": "Timestamp when connection was created (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "database": { - "type": [ - "string", - "null" - ], - "description": "Database name", - "example": "analytics_db" - }, - "defaultSchema": { - "type": [ - "string", - "null" - ], - "description": "Default schema for the connection", - "example": "public" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when connection was deleted (ISO 8601)", - "example": null - }, - "dialect": { - "type": "string", - "enum": [ - "snowflake", - "bigquery", - "redshift", - "postgres", - "mysql", - "mariadb", - "databricks", - "databricks_lakebase", - "trino", - "athena", - "duckdb", - "motherduck", - "sqlserver", - "clickhouse", - "singlestore" - ], - "description": "Database dialect type", - "example": "snowflake" - }, - "environmentConnectionSwitchesSchemaModel": { - "type": [ - "boolean", - "null" - ], - "description": "Whether environment connections switch schema model", - "example": false - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection identifier", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "name": { - "type": "string", - "description": "Connection display name", - "example": "Production Snowflake" - }, - "updatedAt": { - "type": "string", - "description": "Timestamp when connection was last updated (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "userAttributeNameForConnectionEnvironments": { - "type": [ - "string", - "null" - ], - "description": "User attribute name used for connection environments", - "example": "region" - }, - "userAttributeValuesForDefaultEnvironment": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default user attribute values for the base environment", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "allowBranchConnectionEnvironments", - "baseRole", - "branchConnectionEnvironmentOverridesUserAttr", - "createdAt", - "database", - "defaultSchema", - "deletedAt", - "dialect", - "environmentConnectionSwitchesSchemaModel", - "id", - "name", - "updatedAt", - "userAttributeNameForConnectionEnvironments", - "userAttributeValuesForDefaultEnvironment" - ], - "description": "Connection object", - "title": "Connection" - } - }, - "required": [ - "connection" - ], - "description": "Get connection response", - "title": "ConnectionsGetResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied \u2014 caller lacks READ on the connection" - }, - "404": { - "description": "Connection does not exist" - } - } - }, - "patch": { - "description": "Update connection settings including base role, environment user attributes, and credentials.\n\nCredential fields:\n- `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery)\n- `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication\n\nNote: Credentials are encrypted at rest and never returned in API responses.", - "operationId": "connectionsUpdate", - "summary": "Update connection", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "id", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "baseRole": { - "type": "string", - "description": "Default role to assign to this connection", - "example": "QUERIER" - }, - "environmentUserAttribute": { - "type": [ - "object", - "null" - ], - "properties": { - "attributeName": { - "type": "string", - "description": "Name of the user attribute for environment selection", - "example": "region" - }, - "defaultValues": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default values for the user attribute", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "attributeName", - "defaultValues" - ], - "description": "User attribute settings for connection environments" - }, - "passwordUnencrypted": { - "type": "string", - "description": "New password or service account key. For BigQuery, this must be the JSON service account key file content." - }, - "privateKey": { - "type": "string", - "description": "RSA private key for keypair authentication (Snowflake only). Must be PEM-encoded PKCS#8 format, minimum 2048-bit." - } - }, - "description": "Request body for updating connection attributes and credentials. At least one field must be provided.", - "title": "ConnectionsUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Connection updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Status message describing what was updated", - "example": "Updated connection default role." - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "message", - "success" - ], - "description": "Update connection response", - "title": "ConnectionsUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - at least one field must be provided" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection not found" - } - } - }, - "delete": { - "description": "Archive a connection (move to trash). Archived connections can be restored from the trash in the connection settings UI.\n\nA connection that is already archived returns 410.", - "operationId": "connectionsDelete", - "summary": "Delete connection", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "id", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Connection moved to trash", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Status message describing the result", - "example": "Connection moved to trash." - }, - "success": { - "type": "boolean", - "description": "True when the connection was archived", - "example": true - } - }, - "required": [ - "message", - "success" - ], - "description": "Archive connection response", - "title": "ConnectionsDeleteResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection not found" - }, - "410": { - "description": "Connection has already been archived" - } - } - } - }, - "/api/v1/connections/{connectionId}/dbt": { - "get": { - "operationId": "connectionsDbtGet", - "summary": "Get dbt configuration", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "dbt configuration for the connection", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "type": "object", - "properties": { - "autogenRelationships": { - "type": "boolean", - "description": "Whether relationships are auto-generated from dbt", - "example": true - }, - "branch": { - "type": "string", - "description": "Git branch name", - "example": "main" - }, - "dbtVersion": { - "type": "string", - "description": "dbt version being used", - "example": "Auto" - }, - "enableSemanticLayer": { - "type": "boolean", - "description": "Whether the dbt semantic layer integration is enabled", - "example": false - }, - "enableVirtualSchemas": { - "type": "boolean", - "description": "Whether virtual schemas are enabled", - "example": false - }, - "projectRootPath": { - "type": [ - "string", - "null" - ], - "description": "Path to dbt project root", - "example": "dbt_project" - }, - "sshUrl": { - "type": "string", - "description": "SSH URL for git repository", - "example": "git@github.com:org/repo.git" - }, - "supportsDbt": { - "type": "boolean", - "enum": [ - true - ], - "description": "Indicates dbt is supported and configured", - "example": true - } - }, - "required": [ - "autogenRelationships", - "branch", - "dbtVersion", - "enableSemanticLayer", - "enableVirtualSchemas", - "projectRootPath", - "sshUrl", - "supportsDbt" - ], - "description": "dbt repository configuration response", - "title": "DbtConfiguredResponse" - }, - { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Message explaining dbt status", - "example": "dbt not configured for this connection" - }, - "supportsDbt": { - "type": "boolean", - "description": "Whether the connection dialect supports dbt", - "example": true - } - }, - "required": [ - "message", - "supportsDbt" - ], - "description": "Response when dbt is not configured", - "title": "DbtNotConfiguredResponse" - } - ], - "description": "dbt configuration response", - "title": "ConnectionsDbtGetResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection not found" - } - } - }, - "put": { - "operationId": "connectionsDbtUpdate", - "summary": "Update dbt configuration", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "autogenRelationships": { - "type": "boolean", - "description": "Automatically generate relationships from dbt", - "example": true - }, - "branch": { - "type": "string", - "minLength": 1, - "description": "Git branch name", - "example": "main" - }, - "dbtVersion": { - "type": [ - "string", - "null" - ], - "description": "dbt version to use. Supported: Auto, 1.11, 1.12", - "example": "1.11" - }, - "enableSemanticLayer": { - "type": "boolean", - "default": false, - "description": "Enable dbt semantic layer integration", - "example": false - }, - "enableVirtualSchemas": { - "type": "boolean", - "description": "Enable virtual schemas from dbt", - "example": false - }, - "projectRootPath": { - "anyOf": [ - { - "type": "string", - "pattern": "^(?!\\/)(?!.*\\.\\.)[\\w ./-]+$" - }, - { - "type": "string", - "enum": [ - "" - ] - }, - { - "type": [ - "object", - "null" - ], - "enum": [ - null - ] - }, - { - "type": "null" - } - ], - "default": null, - "description": "Path to dbt project root within repository", - "example": "dbt_project" - }, - "rotateKeys": { - "type": "boolean", - "default": false, - "description": "Rotate SSH deploy keys", - "example": false - }, - "sshUrl": { - "type": "string", - "minLength": 1, - "description": "SSH URL for git repository", - "example": "git@github.com:org/repo.git" - } - }, - "required": [ - "autogenRelationships", - "branch", - "enableVirtualSchemas", - "sshUrl" - ], - "description": "dbt repository configuration", - "title": "ConnectionsDbtUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "dbt configuration updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Success message", - "example": "dbt configuration updated successfully" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "message", - "success" - ], - "description": "dbt update response", - "title": "ConnectionsDbtUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or validation error" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection not found" - } - } - }, - "delete": { - "operationId": "connectionsDbtDelete", - "summary": "Delete dbt configuration", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "dbt configuration deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Success message", - "example": "dbt repository unlinked successfully" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "message", - "success" - ], - "description": "dbt delete response", - "title": "ConnectionsDbtDeleteResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection not found or dbt not configured" - } - } - } - }, - "/api/v1/connections/{connectionId}/dbt/environments": { - "get": { - "description": "List all dbt environments for a connection.", - "operationId": "connectionsDbtEnvironmentsList", - "summary": "List dbt environments", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name" - ], - "default": "name", - "description": "Field to sort results by", - "example": "name" - }, - "required": false, - "description": "Field to sort results by", - "name": "sortField", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of dbt environments", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied or connection does not support dbt" - }, - "404": { - "description": "Connection not found" - } - } - }, - "post": { - "description": "Create a new dbt environment for a connection.", - "operationId": "connectionsDbtEnvironmentsCreate", - "summary": "Create dbt environment", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "dbt environment created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentItem" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied or connection does not support dbt" - }, - "404": { - "description": "Connection not found" - } - } - } - }, - "/api/v1/connections/{connectionId}/dbt/environments/{environmentId}": { - "put": { - "description": "Update an existing dbt environment for a connection.", - "operationId": "connectionsDbtEnvironmentsUpdate", - "summary": "Update dbt environment", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Environment ID", - "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" - }, - "required": true, - "description": "Environment ID", - "name": "environmentId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "dbt environment updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentItem" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied or connection does not support dbt" - }, - "404": { - "description": "Connection or environment not found" - } - } - }, - "delete": { - "description": "Delete a dbt environment from a connection.", - "operationId": "connectionsDbtEnvironmentsDelete", - "summary": "Delete dbt environment", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Environment ID", - "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" - }, - "required": true, - "description": "Environment ID", - "name": "environmentId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "dbt environment deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentDeleteResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied or connection does not support dbt" - }, - "404": { - "description": "Connection or environment not found" - } - } - } - }, - "/api/v1/connections/{connectionId}/schedules": { - "get": { - "operationId": "connectionsSchedulesList", - "summary": "List schema refresh schedules", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "List of schema refresh schedules", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "schedules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "hardRefresh": { - "type": "boolean", - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "hardRefresh", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Schema refresh schedule object", - "title": "ConnectionSchedule" - }, - "description": "List of schema refresh schedules" - } - }, - "required": [ - "schedules" - ], - "description": "List schedules response", - "title": "ConnectionsSchedulesListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection not found" - } - } - }, - "post": { - "operationId": "connectionsSchedulesCreate", - "summary": "Create schema refresh schedule", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "hardRefresh": { - "type": "boolean", - "default": false, - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - } - }, - "required": [ - "schedule", - "timezone" - ], - "description": "Request body for creating a schema refresh schedule", - "title": "ConnectionsSchedulesCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Schema refresh schedule created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "hardRefresh": { - "type": "boolean", - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "hardRefresh", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Created schedule response", - "title": "ConnectionsSchedulesCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid cron expression or timezone" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection not found" - } - } - } - }, - "/api/v1/connections/{connectionId}/schedules/{scheduleId}": { - "get": { - "operationId": "connectionsSchedulesGet", - "summary": "Get schema refresh schedule", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "required": true, - "description": "Schedule ID", - "name": "scheduleId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Schema refresh schedule details", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "hardRefresh": { - "type": "boolean", - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "hardRefresh", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Get schedule response", - "title": "ConnectionsSchedulesGetResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection or schedule not found" - } - } - }, - "put": { - "operationId": "connectionsSchedulesUpdate", - "summary": "Update schema refresh schedule", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "required": true, - "description": "Schedule ID", - "name": "scheduleId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "hardRefresh": { - "type": "boolean", - "default": false, - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - } - }, - "required": [ - "schedule", - "timezone" - ], - "description": "Request body for updating a schema refresh schedule", - "title": "ConnectionsSchedulesUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Schema refresh schedule updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "hardRefresh": { - "type": "boolean", - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "hardRefresh", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Updated schedule response", - "title": "ConnectionsSchedulesUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid cron expression or timezone" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection or schedule not found" - } - } - }, - "delete": { - "operationId": "connectionsSchedulesDelete", - "summary": "Delete schema refresh schedule", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "required": true, - "description": "Schedule ID", - "name": "scheduleId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Schema refresh schedule deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Delete schedule response", - "title": "ConnectionsSchedulesDeleteResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection or schedule not found" - } - } - } - }, - "/api/v1/connection-environments": { - "post": { - "operationId": "connectionEnvironmentsCreate", - "summary": "Create connection environments", - "tags": [ - "Connections" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "environmentConnectionIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "description": "IDs of connections to use as environments", - "example": [ - "550e8400-e29b-41d4-a716-446655440002", - "550e8400-e29b-41d4-a716-446655440003" - ] - } - }, - "required": [ - "baseConnectionId", - "environmentConnectionIds" - ], - "description": "Request body for creating connection environments", - "title": "ConnectionsEnvironmentsCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Connection environments created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connectionEnvironments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the environment connection", - "example": "550e8400-e29b-41d4-a716-446655440002" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection environment identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "baseConnectionId", - "connectionId", - "id", - "userAttributeValues" - ], - "description": "Connection environment object", - "title": "ConnectionEnvironment" - }, - "description": "Created connection environments" - } - }, - "required": [ - "connectionEnvironments" - ], - "description": "Create connection environments response", - "title": "ConnectionsEnvironmentsCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or connection IDs" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - }, - "404": { - "description": "Base connection or environment connection not found" - } - } - } - }, - "/api/v1/connection-environments/{id}": { - "put": { - "operationId": "connectionEnvironmentsUpdate", - "summary": "Update connection environment", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection environment ID", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "required": true, - "description": "Connection environment ID", - "name": "id", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "userAttributeValues" - ], - "description": "Request body for updating a connection environment", - "title": "ConnectionsEnvironmentsUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Connection environment updated successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Update connection environment response", - "title": "ConnectionsEnvironmentsUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - }, - "404": { - "description": "Connection environment not found" - } - } - }, - "delete": { - "operationId": "connectionEnvironmentsDelete", - "summary": "Delete connection environment", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection environment ID", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "required": true, - "description": "Connection environment ID", - "name": "id", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Connection environment deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Delete connection environment response", - "title": "ConnectionsEnvironmentsDeleteResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - }, - "404": { - "description": "Connection environment not found" - } - } - } - }, - "/api/v1/content": { - "get": { - "operationId": "contentList", - "summary": "List content", - "tags": [ - "Content" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by creator user ID" - }, - "required": false, - "description": "Filter by creator user ID", - "name": "creatorId", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by folder ID (cannot be used with path)" - }, - "required": false, - "description": "Filter by folder ID (cannot be used with path)", - "name": "folderId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of fields to include (e.g., _count,labels)" - }, - "required": false, - "description": "Comma-separated list of fields to include (e.g., _count,labels)", - "name": "include", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by folder path (cannot be used with folderId)", - "example": "/reports/sales" - }, - "required": false, - "description": "Filter by folder path (cannot be used with folderId)", - "name": "path", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Filter by share scope", - "example": "organization" - }, - "required": false, - "description": "Filter by share scope", - "name": "scope", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "description": "Sort direction", - "example": "asc" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name", - "favorites" - ], - "description": "Field to sort by", - "example": "name" - }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of content (documents and folders)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ContentListResponse" - } - } - } - }, - "400": { - "description": "Invalid query parameters (cannot use both folderId and path)" - }, - "401": { - "description": "Authentication required" - }, - "404": { - "description": "Folder not found (when filtering by path)" - } - } - } - }, - "/api/v1/dashboards/{identifier}/download": { - "post": { - "operationId": "dashboardsDownload", - "summary": "Initiate dashboard download", - "tags": [ - "Dashboards" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" - }, - "required": true, - "description": "Dashboard identifier (short ID or UUID)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DashboardsDownloadBody" - } - } - } - }, - "responses": { - "200": { - "description": "Download job initiated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DashboardsDownloadResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or filter configuration" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - cannot download this dashboard" - }, - "404": { - "description": "Dashboard not found" - }, - "409": { - "description": "Download already in progress for this dashboard" - }, - "500": { - "description": "Failed to initiate download" - } - } - } - }, - "/api/v1/dashboards/{identifier}/download/{jobId}": { - "get": { - "operationId": "dashboardsDownloadFile", - "summary": "Get download file", - "tags": [ - "Dashboards" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" - }, - "required": true, - "description": "Dashboard identifier (short ID or UUID)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Download job ID (UUID)", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Download job ID (UUID)", - "name": "jobId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "File ready - binary content streamed" - }, - "202": { - "description": "Download job still in progress" - }, - "401": { - "description": "Authentication required" - }, - "404": { - "description": "Dashboard or download job not found" - }, - "410": { - "description": "Download job failed" - }, - "500": { - "description": "Failed to retrieve download artifact" - } - } - } - }, - "/api/v1/dashboards/{identifier}/download/{jobId}/status": { - "get": { - "operationId": "dashboardsDownloadStatus", - "summary": "Get download job status", - "tags": [ - "Dashboards" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" - }, - "required": true, - "description": "Dashboard identifier (short ID or UUID)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Download job ID (UUID)", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Download job ID (UUID)", - "name": "jobId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Download job status" - }, - "401": { - "description": "Authentication required" - }, - "404": { - "description": "Dashboard or download job not found" - } - } - } - }, - "/api/v1/dashboards/{identifier}/filters": { - "get": { - "operationId": "dashboardsGetFilters", - "summary": "Get dashboard filters", - "tags": [ - "Dashboards" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" - }, - "required": true, - "description": "Dashboard identifier (short ID or UUID)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Dashboard filter and control configuration", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DashboardFiltersResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - VIEWER role required" - }, - "404": { - "description": "Dashboard not found" - } - } - }, - "patch": { - "operationId": "dashboardsUpdateFilters", - "summary": "Update dashboard filters", - "tags": [ - "Dashboards" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" - }, - "required": true, - "description": "Dashboard identifier (short ID or UUID)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DashboardsUpdateFiltersBody" - } - } - } - }, - "responses": { - "200": { - "description": "Filters updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DashboardFiltersResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - must include at least one filter, control, or filterOrder" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - EDITOR role required" - }, - "404": { - "description": "Dashboard not found or document does not have a dashboard" - }, - "409": { - "description": "Conflict - draft already exists. Set clearExistingDraft to true to proceed." - } - } - } - }, - "/api/v1/documents": { - "get": { - "operationId": "documentsList", - "summary": "List documents", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by creator membership ID" - }, - "required": false, - "description": "Filter by creator membership ID", - "name": "creatorId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination" - }, - "required": false, - "description": "Cursor for pagination", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by folder ID" - }, - "required": false, - "description": "Filter by folder ID", - "name": "folderId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", - "example": "_count,labels" - }, - "required": false, - "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", - "name": "include", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of label names to filter by", - "example": "verified,important" - }, - "required": false, - "description": "Comma-separated list of label names to filter by", - "name": "labels", - "in": "query" - }, - { - "schema": { - "type": "integer", - "exclusiveMinimum": 0, - "default": 50, - "description": "Number of records per page" - }, - "required": false, - "description": "Number of records per page", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name", - "favorites", - "updatedAt", - "visits" - ], - "default": "name", - "description": "Field to sort by" - }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter documents visible to this membership ID" - }, - "required": false, - "description": "Filter documents visible to this membership ID", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Paginated list of documents", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - } - } - }, - "post": { - "operationId": "documentsCreate", - "summary": "Create document", - "tags": [ - "Documents" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Document created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or branch not found" - } - } - } - }, - "/api/v1/documents/{identifier}": { - "get": { - "description": "Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a document, modify the response, and PUT it back to update. Only dashboard documents are supported; analysis documents return 400.", - "operationId": "documentsGet", - "summary": "Get document", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Document details", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsGetResponse" - } - } - } - }, - "400": { - "description": "Analysis documents are not supported" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Insufficient permissions to view the document" - }, - "404": { - "description": "Document not found" - } - } - }, - "put": { - "deprecated": true, - "description": "**Deprecated** \u2014 use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). Scheduled for removal on July 31, 2026 (see the `Sunset` response header).\n\nUpdates a document with the specified identifier. This endpoint performs a full resource replacement \u2014 all required fields must be provided and existing query presentations are replaced entirely. Only dashboard documents are supported; analysis documents and documents without an associated dashboard return 400. For published documents, the update goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", - "operationId": "documentsPut", - "summary": "Replace document (full replacement)", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsPutBody" - } - } - } - }, - "responses": { - "200": { - "description": "Document replaced successfully", - "headers": { - "Deprecation": { - "schema": { - "type": "string", - "enum": [ - "true" - ], - "description": "Marks the endpoint as deprecated." - }, - "required": true, - "description": "Marks the endpoint as deprecated." - }, - "Link": { - "schema": { - "type": "string", - "description": "Points to the v2 successor resource.", - "example": "; rel=\"successor-version\"" - }, - "required": true, - "description": "Points to the v2 successor resource." - }, - "Sunset": { - "schema": { - "type": "string", - "description": "Date the endpoint will be removed, in RFC 1123 form (RFC 8594).", - "example": "Fri, 31 Jul 2026 00:00:00 GMT" - }, - "required": true, - "description": "Date the endpoint will be removed, in RFC 1123 form (RFC 8594)." - } - }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsPutResponse" - } - } - } - }, - "400": { - "description": "Invalid request body, missing required fields, or validation error (also returned for analysis documents and documents without an associated dashboard)" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Insufficient permissions to update the document" - }, - "404": { - "description": "Document not found" - }, - "409": { - "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" - } - } - }, - "patch": { - "deprecated": true, - "description": "**Deprecated** \u2014 use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). Scheduled for removal on July 31, 2026 (see the `Sunset` response header).\n\nUpdates a document's name, description, and/or identifier. This is a partial update \u2014 only provided fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. When `identifier` is changed, the previous identifier is retained in the document identifier history and continues to redirect. For published documents, the update goes through a draft/publish workflow automatically.", - "operationId": "documentsUpdate", - "summary": "Rename document", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Document updated successfully", - "headers": { - "Deprecation": { - "schema": { - "type": "string", - "enum": [ - "true" - ], - "description": "Marks the endpoint as deprecated." - }, - "required": true, - "description": "Marks the endpoint as deprecated." - }, - "Link": { - "schema": { - "type": "string", - "description": "Points to the v2 successor resource.", - "example": "; rel=\"successor-version\"" - }, - "required": true, - "description": "Points to the v2 successor resource." - }, - "Sunset": { - "schema": { - "type": "string", - "description": "Date the endpoint will be removed, in RFC 1123 form (RFC 8594).", - "example": "Fri, 31 Jul 2026 00:00:00 GMT" - }, - "required": true, - "description": "Date the endpoint will be removed, in RFC 1123 form (RFC 8594)." - } - }, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or validation error (e.g. missing name/description/identifier, name too long, identifier already in use)" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - EDITOR role required" - }, - "404": { - "description": "Document not found" - }, - "409": { - "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" - } - } - }, - "delete": { - "operationId": "documentsDelete", - "summary": "Delete document", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Document deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - MANAGER role required" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v1/documents/{identifier}/queries": { - "get": { - "operationId": "documentsGetQueries", - "summary": "List document queries", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "responses": { - "200": { - "description": "List of queries in the document", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsGetQueriesResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v1/documents/{identifier}/move": { - "put": { - "operationId": "documentsMove", - "summary": "Move document", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsMoveBody" - } - } - } - }, - "responses": { - "200": { - "description": "Document moved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid folder path or scope" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - MANAGER role required" - }, - "404": { - "description": "Document or folder not found" - } - } - } - }, - "/api/v1/documents/{identifier}/permissions": { - "get": { - "operationId": "documentsGetPermissions", - "summary": "Get document permissions", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "User membership ID to check permissions for" - }, - "required": true, - "description": "User membership ID to check permissions for", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "User permissions for the document", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsGetPermissionsResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document or user not found" - } - } - }, - "put": { - "operationId": "documentsUpdatePermissionSettings", - "summary": "Update document permission settings", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpdatePermissionSettingsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Permission settings updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - MANAGER role required" - }, - "404": { - "description": "Document not found" - } - } - }, - "post": { - "operationId": "documentsAddPermits", - "summary": "Add document permits", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsAddPermitsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Permissions added successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - userIds or userGroupIds required" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - MANAGER role required" - }, - "404": { - "description": "Document not found" - } - } - }, - "patch": { - "operationId": "documentsUpdatePermits", - "summary": "Update document permits", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpdatePermitsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Permissions updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - userIds or userGroupIds required" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - MANAGER role required" - }, - "404": { - "description": "Document not found" - } - } - }, - "delete": { - "operationId": "documentsRevokePermits", - "summary": "Revoke document permits", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsRevokePermitsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Permissions revoked successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - userIds or userGroupIds required" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - MANAGER role required" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v1/documents/{identifier}/draft": { - "post": { - "operationId": "documentsCreateDraft", - "summary": "Create document draft", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsCreateDraftBody" - } - } - } - }, - "responses": { - "200": { - "description": "Draft created or existing draft returned", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsCreateDraftResponse" - } - } - } - }, - "400": { - "description": "Document is not eligible for publishing workflow" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - EDITOR role required" - }, - "404": { - "description": "Document or branch not found" - } - } - }, - "delete": { - "operationId": "documentsDiscardDraft", - "summary": "Discard document draft", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsDiscardDraftBody" - } - } - } - }, - "responses": { - "200": { - "description": "Draft discarded successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsDiscardDraftResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document or draft not found" - } - } - } - }, - "/api/v1/documents/{identifier}/drafts": { - "get": { - "description": "Lists drafts for a document with branch context. By default only active drafts are returned; pass `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by `createdAt` descending.", - "operationId": "documentsListDrafts", - "summary": "List document drafts", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized \u2014 when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", - "example": "archived" - }, - "required": false, - "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized \u2014 when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", - "name": "include", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of drafts for the document", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsListDraftsResponse" - } - } - } - }, - "400": { - "description": "Invalid query parameters" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Insufficient permissions to view the document" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v1/documents/{identifier}/duplicate": { - "post": { - "operationId": "documentsDuplicate", - "summary": "Duplicate document", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsDuplicateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Document duplicated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsDuplicateResponse" - } - } - } - }, - "400": { - "description": "Invalid name or folder path" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document or folder not found" - } - } - } - }, - "/api/v1/documents/{identifier}/upgrade": { - "post": { - "description": "Upgrades a document to the advanced dashboard layout (the \"File > Upgrade layout\" UI action). No-ops when the document already has advanced layout. For published documents the upgrade goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", - "operationId": "documentsUpgradeLayout", - "summary": "Upgrade dashboard layout", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpgradeLayoutBody" - } - } - } - }, - "responses": { - "200": { - "description": "Layout upgraded, or no-op if the document already had advanced layout", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpgradeLayoutResponse" - } - } - } - }, - "400": { - "description": "Document does not have a dashboard to upgrade" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" - }, - "409": { - "description": "A draft already exists for the published document; set clearExistingDraft to override" - } - } - } - }, - "/api/v1/documents/{identifier}/favorite": { - "put": { - "operationId": "documentsAddFavorite", - "summary": "Add document to favorites", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "204": { - "description": "Favorite added successfully" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" - } - } - }, - "delete": { - "operationId": "documentsRemoveFavorite", - "summary": "Remove document from favorites", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "204": { - "description": "Favorite removed successfully" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v1/documents/{identifier}/labels": { - "patch": { - "operationId": "documentsBulkUpdateLabels", - "summary": "Bulk update document labels", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Labels updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsResponse" - } - } - } - }, - "400": { - "description": "Invalid request - at least one label must be specified" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v1/documents/{identifier}/labels/{labelName}": { - "put": { - "operationId": "documentsAddLabel", - "summary": "Add label to document", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier", - "example": "abc123" - }, - "required": true, - "description": "Document identifier", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "required": true, - "description": "Label name", - "name": "labelName", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "204": { - "description": "Label added successfully" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document or label not found" - } - } - }, - "delete": { - "operationId": "documentsRemoveLabel", - "summary": "Remove label from document", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier", - "example": "abc123" - }, - "required": true, - "description": "Document identifier", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "required": true, - "description": "Label name", - "name": "labelName", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "204": { - "description": "Label removed successfully" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v1/documents/{identifier}/transfer-ownership": { - "put": { - "operationId": "documentsTransferOwnership", - "summary": "Transfer document ownership", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsTransferOwnershipBody" - } - } - } - }, - "responses": { - "200": { - "description": "Ownership transferred successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid user ID" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - MANAGER role or owner required" - }, - "404": { - "description": "Document or user not found" - } - } - } - }, - "/api/v1/documents/{identifier}/access-list": { - "get": { - "operationId": "documentsAccessList", - "summary": "List document access principals", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction (default: asc)", - "example": "desc" - }, - "required": false, - "description": "Sort direction (default: asc)", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Field to sort results by" - }, - "required": false, - "description": "Field to sort results by", - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "direct", - "folder" - ], - "description": "Filter by access source: direct or folder" - }, - "required": false, - "description": "Filter by access source: direct or folder", - "name": "accessSource", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "user", - "userGroup" - ], - "description": "Filter by principal type: user or userGroup" - }, - "required": false, - "description": "Filter by principal type: user or userGroup", - "name": "type", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of users and groups with access", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsAccessListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - VIEWER role required" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v1/documents/{identifier}/favorites": { - "get": { - "description": "Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need to preserve favorites when replacing documents, without iterating every user in the organization.", - "operationId": "documentsListFavorites", - "summary": "List users who favorited the document", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction by favoritedAt (default: asc \u2014 oldest first)", - "example": "desc" - }, - "required": false, - "description": "Sort direction by favoritedAt (default: asc \u2014 oldest first)", - "name": "sortDirection", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Paginated list of users who favorited the document", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsListFavoritesResponse" - } - } - } - }, - "400": { - "description": "Invalid query parameters" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied \u2014 caller lacks MANAGER on the document, or used a user-scoped (personal access token) API key (org-scoped only)" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v2/documents": { - "post": { - "description": "Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body \u2014 `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed.\n\nWhen `containers` is omitted, every dashboard-eligible tile is auto-placed in a default layout. When `containers` is present, it fully defines the layout \u2014 tiles it does not reference are stored but not rendered. Send `containers: null` to create a workbook-only document with no dashboard (`controls` and `settings` must then be omitted); an empty `containers: []` is rejected.\n\nThe new document is published live before the response returns. As a first publish of brand-new content it is not subject to the org\u2019s `requirePullRequestToPublish` policy (which gates edits to existing content).", - "operationId": "documentsV2Create", - "summary": "Create document", - "tags": [ - "Documents" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2CreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Document created and published successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2CreateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded), or the `identifier` is already in use." - }, - "401": { - "description": "Authentication required." - }, - "403": { - "description": "Insufficient permissions to create a document on this model." - }, - "404": { - "description": "Base model or branch not found." - }, - "405": { - "description": "Method not allowed." - } - } - } - }, - "/api/v2/documents/{identifier}": { - "get": { - "description": "Read the document's published state \u2014 draft edits are never surfaced here. When a draft exists, read it via `GET /api/v2/documents/{identifier}/draft/{draftIdentifier}` before round-tripping the response into a draft PATCH, so you patch the draft's own content rather than published content over it. Returns the full `DocumentsV2ReadResponse` shape.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) \u2014 the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", - "operationId": "documentsV2Get", - "summary": "Read document state", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "example": "abc123" - }, - "required": true, - "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "enum": [ - "0", - "1", - "true", - "false" - ], - "description": "Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless." - }, - "required": false, - "description": "Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless.", - "name": "pretty", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Document state. A workbook-only document (no dashboard layout yet) returns only the workbook-scoped fields (`name`, `description`, `queryPresentations`); the dashboard-scoped `containers`, `controls`, and `settings` are omitted until a layout exists.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2ReadResponse" - } - } - } - }, - "401": { - "description": "Authentication required." - }, - "403": { - "description": "Insufficient permissions to read the document." - }, - "404": { - "description": "Document not found." - }, - "422": { - "description": "The document cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." - } - } - } - }, - "/api/v2/documents/{identifier}/draft": { - "patch": { - "description": "Create a new draft on the published document and apply the patch. No auto-publish \u2014 the response includes the new `draftIdentifier` for follow-up calls.\n\nPass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main (unpublished) workspace.", - "operationId": "documentsV2PatchDraft", - "summary": "Create draft and patch document", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "example": "abc123" - }, - "required": true, - "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2CreateDraftBody" - } - } - } - }, - "responses": { - "200": { - "description": "Draft created and patch applied successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded, or a `modelId` that differs from the document\u2019s immutable base model)." - }, - "401": { - "description": "Authentication required." - }, - "403": { - "description": "Insufficient permissions to update the document." - }, - "404": { - "description": "Document or branch not found." - }, - "405": { - "description": "Method not allowed." - }, - "409": { - "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document \u2014 retry." - }, - "422": { - "description": "The document cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only document patched without a `containers` payload (or with an empty one)." - } - } - } - }, - "/api/v2/documents/{identifier}/draft/{draftIdentifier}": { - "get": { - "description": "Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape \u2014 same as the live-state read endpoint.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) \u2014 the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", - "operationId": "documentsV2GetDraft", - "summary": "Read draft state", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", - "example": "def456" - }, - "required": true, - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", - "name": "draftIdentifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Published document identifier.", - "example": "abc123" - }, - "required": true, - "description": "Published document identifier.", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "enum": [ - "0", - "1", - "true", - "false" - ], - "description": "Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless." - }, - "required": false, - "description": "Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless.", - "name": "pretty", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Draft state.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2ReadResponse" - } - } - } - }, - "401": { - "description": "Authentication required." - }, - "403": { - "description": "Insufficient permissions to read the draft." - }, - "404": { - "description": "Document or draft not found." - }, - "422": { - "description": "The draft cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." - } - } - }, - "patch": { - "description": "Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply \u2014 no draft creation, no publish.", - "operationId": "documentsV2PatchDraftByIdentifier", - "summary": "Patch draft", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", - "example": "def456" - }, - "required": true, - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", - "name": "draftIdentifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Published document identifier.", - "example": "abc123" - }, - "required": true, - "description": "Published document identifier.", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" - } - } - } - }, - "responses": { - "200": { - "description": "Patch applied to draft successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded, or a `modelId` that differs from the document\u2019s immutable base model)." - }, - "401": { - "description": "Authentication required." - }, - "403": { - "description": "Insufficient permissions to update the draft." - }, - "404": { - "description": "Document or draft not found." - }, - "405": { - "description": "Method not allowed." - }, - "409": { - "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document \u2014 retry." - }, - "422": { - "description": "The draft cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only draft patched without a `containers` payload (or with an empty one)." - } - } - } - }, - "/api/v2/documents/{identifier}/draft/publish": { - "post": { - "description": "Publish the document's current main (non-branch) draft, promoting it to the published version. No request body \u2014 the draft is consumed, so the response echoes the now-published document metadata.\n\nOnly the main draft is publishable here; a branch-attached draft is published by merging its branch (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft returns 404. Documents that require a pull request to publish return 400.", - "operationId": "documentsV2PublishDraft", - "summary": "Publish draft", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "example": "abc123" - }, - "required": true, - "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "name": "identifier", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Draft published successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2PublishDraftResponse" - } - } - } - }, - "400": { - "description": "The document requires a pull request to publish (response detail: \"Can't publish because this document can only be edited through a branch\")." - }, - "401": { - "description": "Authentication required." - }, - "403": { - "description": "Insufficient permissions to publish the draft." - }, - "404": { - "description": "Document not found, or it has no main draft to publish (a branch-attached draft is published by merging its branch)." - }, - "405": { - "description": "Method not allowed." - }, - "409": { - "description": "The target is not a published document." - } - } - } - }, - "/api/v2/documents/{identifier}/identifier": { - "put": { - "description": "Rename a published document's identifier. The change is applied live and immediately \u2014 it does not go through the draft/publish workflow \u2014 and the former identifier is recorded in the document's rename history.\n\nOnly published documents can be renamed. A draft target returns 409; an unknown or archived target returns 404. The new identifier must be a valid slug (otherwise 400) and unused by any other document in the organization (otherwise 409).", - "operationId": "documentsV2UpdateIdentifier", - "summary": "Rename document identifier", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "example": "abc123" - }, - "required": true, - "description": "Document identifier \u2014 either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "name": "identifier", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2UpdateIdentifierBody" - } - } - } - }, - "responses": { - "200": { - "description": "Identifier updated successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2UpdateIdentifierResponse" - } - } - } - }, - "400": { - "description": "Invalid identifier format." - }, - "401": { - "description": "Authentication required." - }, - "403": { - "description": "Insufficient permissions to rename the document." - }, - "404": { - "description": "Document not found or archived." - }, - "405": { - "description": "Method not allowed." - }, - "409": { - "description": "The target is a draft rather than a published document, or the requested identifier is already in use by another document." - } - } - } - }, - "/api/v1/embed/sso/generate-session": { - "post": { - "operationId": "embedSsoGenerateSession", - "summary": "Generate embedded SSO session", - "tags": [ - "Embed" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EmbedSsoGenerateSessionBody" - } - } - } - }, - "responses": { - "200": { - "description": "Session token generated", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EmbedSsoGenerateSessionResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required (API key with embed scope)" - }, - "403": { - "description": "Permission denied - embed not enabled" - } - } - } - }, - "/api/v1/ai/eval/prompt-sets": { - "get": { - "description": "List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt sets for every shared model the caller can access. Requires at least the Querier role on each requested model.", - "operationId": "aiEvalPromptSetsList", - "summary": "List eval prompt sets", - "tags": [ - "AI Eval" - ], - "parameters": [ - { - "schema": { - "type": "string", - "enum": [ - "true", - "false" - ], - "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", - "example": "false" - }, - "required": false, - "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", - "name": "archived", - "in": "query" - }, - { - "schema": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`)." - }, - "required": false, - "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`).", - "name": "model_ids", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of prompt sets, sorted alphabetically by name.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsListResponse" - } - } - } - }, - "400": { - "description": "Invalid query params (e.g. `model_ids` contains a non-UUID, or `archived` is not `true`/`false`).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions. The caller must have at least the Querier role on each requested model.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError403" - } - } - } - }, - "404": { - "description": "No eval-accessible models for this caller.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError404" - } - } - } - } - } - }, - "post": { - "description": "Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional prompts can be added later via PATCH.", - "operationId": "aiEvalPromptSetsCreate", - "summary": "Create an eval prompt set", - "tags": [ - "AI Eval" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Prompt set created successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions. The caller must have at least the Querier role on the model.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError403" - } - } - } - }, - "422": { - "description": "Prompt count exceeds the organization's per-set cap (default 25, higher for orgs with the `ai-eval-extra-prompts` flag).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError422" - } - } - } - } - } - } - }, - "/api/v1/ai/eval/prompt-sets/{promptSetId}": { - "get": { - "description": "Get a single prompt set with all of its prompts.", - "operationId": "aiEvalPromptSetsGet", - "summary": "Get an eval prompt set", - "tags": [ - "AI Eval" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the eval prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "The unique identifier of the eval prompt set.", - "name": "promptSetId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Prompt set details.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsGetResponse" - } - } - } - }, - "400": { - "description": "Invalid `promptSetId` \u2014 must be a UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError403" - } - } - } - }, - "404": { - "description": "Prompt set not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError404" - } - } - } - } - } - }, - "patch": { - "description": "Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully replaces the existing list \u2014 existing prompts omitted from the list are deleted, entries without an `id` are created, and entries with a matching `id` are updated in place.", - "operationId": "aiEvalPromptSetsUpdate", - "summary": "Update an eval prompt set", - "tags": [ - "AI Eval" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the eval prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "The unique identifier of the eval prompt set.", - "name": "promptSetId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Prompt set updated successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError403" - } - } - } - }, - "404": { - "description": "Prompt set not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError404" - } - } - } - }, - "422": { - "description": "A `prompts[].id` in the request does not belong to this prompt set, or the prompt count exceeds the organization's per-set cap (default 25, higher for orgs with the `ai-eval-extra-prompts` flag).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError422" - } - } - } - } - } - }, - "delete": { - "description": "Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight agentic job associated with the set; the returned `cancelled_job_count` reports how many were cancelled. The archive is committed before run cancellations start. Cancellation is best-effort \u2014 the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt set is already archived. The call is idempotent \u2014 retrying drains any remaining runs.", - "operationId": "aiEvalPromptSetsArchive", - "summary": "Archive an eval prompt set", - "tags": [ - "AI Eval" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the eval prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "The unique identifier of the eval prompt set.", - "name": "promptSetId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Prompt set archived successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsDeleteResponse" - } - } - } - }, - "400": { - "description": "Invalid `promptSetId` \u2014 must be a UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError403" - } - } - } - }, - "404": { - "description": "Prompt set not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError404" - } - } - } - }, - "500": { - "description": "Archive committed but a run-cancellation failed; the set is already archived \u2014 safe to retry.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError500" - } - } - } - } - } - } - }, - "/api/v1/ai/eval/prompt-sets/{promptSetId}/unarchive": { - "post": { - "description": "Restore an archived prompt set.", - "operationId": "aiEvalPromptSetsUnarchive", - "summary": "Restore an archived eval prompt set", - "tags": [ - "AI Eval" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the eval prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "The unique identifier of the eval prompt set.", - "name": "promptSetId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Prompt set restored successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsUnarchiveResponse" - } - } - } - }, - "400": { - "description": "Invalid `promptSetId` \u2014 must be a UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError403" - } - } - } - }, - "404": { - "description": "Prompt set not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError404" - } - } - } - } - } - } - }, - "/api/v1/ai/eval/runs": { - "get": { - "description": "List runs for a prompt set, newest first, filtered to runs whose model the caller can access. The `prompt_set_id` query parameter is required.", - "operationId": "aiEvalRunsList", - "summary": "List eval runs", - "tags": [ - "AI Eval" - ], - "parameters": [ - { - "schema": { - "type": "string", - "enum": [ - "true", - "false" - ], - "description": "When `true`, returns archived runs instead of active ones. Defaults to `false`.", - "example": "false" - }, - "required": false, - "description": "When `true`, returns archived runs instead of active ones. Defaults to `false`.", - "name": "archived", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Required \u2014 the prompt set whose runs should be listed.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Required \u2014 the prompt set whose runs should be listed.", - "name": "prompt_set_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of runs for the prompt set.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalRunsListResponse" - } - } - } - }, - "400": { - "description": "Missing or invalid `prompt_set_id`.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError403" - } - } - } - }, - "404": { - "description": "Prompt set not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError404" - } - } - } - } - } - }, - "post": { - "description": "Create and start a new run against an existing prompt set. The run enqueues one agentic job per prompt and begins executing immediately. Returns the newly created run with its initial per-prompt result rows.", - "operationId": "aiEvalRunsCreate", - "summary": "Start an eval run", - "tags": [ - "AI Eval" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalRunsCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Run created and jobs enqueued.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalRunsCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions. The caller must have at least the Querier role on the prompt set's model.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError403" - } - } - } - }, - "404": { - "description": "The prompt set was not found, or `run_config.branch_id` does not match an existing branch in the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError404" - } - } - } - }, - "422": { - "description": "`run_config.branch_id` does not belong to the prompt set's model.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError422" - } - } - } - }, - "429": { - "description": "Per-user active-run cap reached.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError429" - } - } - } - }, - "500": { - "description": "Run created and jobs enqueued, but it could not be re-read for the response. The run exists \u2014 list runs for the prompt set to find it rather than retrying, since a retry starts a duplicate run.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError500" - } - } - } - }, - "503": { - "description": "AI eval is paused for this organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError503" - } - } - } - } - } - } - }, - "/api/v1/ai/eval/runs/{runId}": { - "get": { - "description": "Get an eval run with every per-prompt result row, including the underlying agentic job state and any scoring data.", - "operationId": "aiEvalRunsGet", - "summary": "Get an eval run", - "tags": [ - "AI Eval" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the eval run.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "required": true, - "description": "The unique identifier of the eval run.", - "name": "runId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Run detail.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalRunsGetResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError403" - } - } - } - }, - "404": { - "description": "Run not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError404" - } - } - } - } - } - }, - "delete": { - "description": "Archive (soft-delete) an eval run. Any non-terminal per-prompt agentic jobs are cancelled as part of the archive (best-effort), and a still-RUNNING run is flipped to CANCELLED before archival. The call is idempotent; archiving an already-terminal or already-archived run is a no-op.", - "operationId": "aiEvalRunsArchive", - "summary": "Archive an eval run", - "tags": [ - "AI Eval" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the eval run.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "required": true, - "description": "The unique identifier of the eval run.", - "name": "runId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Run archived successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalRunsDeleteResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError403" - } - } - } - }, - "404": { - "description": "Run not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError404" - } - } - } - }, - "500": { - "description": "A still-running run may already be flipped to CANCELLED and archived even though the rest of the cascade failed \u2014 safe to retry.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError500" - } - } - } - } - } - } - }, - "/api/v1/ai/eval/runs/{runId}/cancel": { - "post": { - "description": "Cancel an in-flight eval run. Any non-terminal per-prompt jobs are cancelled and the run is archived \u2014 the response returns the updated run inline (`status: CANCELLED`, `is_archived: true`); use `/unarchive` to surface it in the default `archived=false` list again.", - "operationId": "aiEvalRunsCancel", - "summary": "Cancel an eval run", - "tags": [ - "AI Eval" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the eval run.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "required": true, - "description": "The unique identifier of the eval run.", - "name": "runId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Cancellation processed.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalRunsCancelResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError403" - } - } - } - }, - "404": { - "description": "Run not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError404" - } - } - } - }, - "500": { - "description": "The run was cancelled and archived, but could not be re-read for the response \u2014 safe to retry.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError500" - } - } - } - } - } - } - }, - "/api/v1/ai/eval/runs/{runId}/unarchive": { - "post": { - "description": "Restore an archived eval run.", - "operationId": "aiEvalRunsUnarchive", - "summary": "Restore an archived eval run", - "tags": [ - "AI Eval" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the eval run.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "required": true, - "description": "The unique identifier of the eval run.", - "name": "runId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Run restored successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalRunsUnarchiveResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError403" - } - } - } - }, - "404": { - "description": "Run not found.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError404" - } - } - } - } - } - } - }, - "/api/v1/folders": { - "get": { - "operationId": "foldersList", - "summary": "List folders", - "tags": [ - "Folders" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Cursor for pagination" - }, - "required": false, - "description": "Cursor for pagination", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of fields to include (_count, labels, onlySharedWithMe). onlySharedWithMe returns only folders shared with the user, cannot be combined with ownerId or path, and when used with org-scoped API keys requires the userId query parameter. For user-scoped keys (PAT), userId is auto-inferred from the token.", - "example": "_count,labels" - }, - "required": false, - "description": "Comma-separated list of fields to include (_count, labels, onlySharedWithMe). onlySharedWithMe returns only folders shared with the user, cannot be combined with ownerId or path, and when used with org-scoped API keys requires the userId query parameter. For user-scoped keys (PAT), userId is auto-inferred from the token.", - "name": "include", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of labels to filter by" - }, - "required": false, - "description": "Comma-separated list of labels to filter by", - "name": "labels", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by owner user ID" - }, - "required": false, - "description": "Filter by owner user ID", - "name": "ownerId", - "in": "query" - }, - { - "schema": { - "type": [ - "number", - "null" - ], - "description": "Number of results per page", - "example": 20 - }, - "required": false, - "description": "Number of results per page", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by exact path" - }, - "required": false, - "description": "Filter by exact path", - "name": "path", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Filter by share scope" - }, - "required": false, - "description": "Filter by share scope", - "name": "scope", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "description": "Sort direction" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name", - "createdAt", - "updatedAt", - "favorites", - "path" - ], - "description": "Field to sort by" - }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "User membership ID. Only used with onlySharedWithMe include field. Required for org-scoped API keys; auto-inferred from the token for user-scoped keys (PAT)." - }, - "required": false, - "description": "User membership ID. Only used with onlySharedWithMe include field. Required for org-scoped API keys; auto-inferred from the token for user-scoped keys (PAT).", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Paginated list of folders", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "404": { - "description": "Folder not found (when filtering by path)" - } - } - }, - "post": { - "operationId": "foldersCreate", - "summary": "Create a folder", - "tags": [ - "Folders" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Folder created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body, scope mismatch with parent folder, or cannot create under restricted folder owned by another user" - }, - "401": { - "description": "Authentication required" - }, - "404": { - "description": "Parent folder not found" - } - } - } - }, - "/api/v1/folders/{folderId}": { - "delete": { - "description": "Deletes a folder. By default, non-empty folders (containing documents or sub-folders) return a 400 error. Pass `force=true` to recursively archive all documents (soft-delete to trash) and permanently remove all sub-folders before deleting the target folder. Force delete is limited to 100 total items (documents + sub-folders).", - "operationId": "foldersDelete", - "summary": "Delete a folder", - "tags": [ - "Folders" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the folder", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Unique identifier for the folder", - "name": "folderId", - "in": "path" - }, - { - "schema": { - "type": [ - "boolean", - "null" - ], - "default": false, - "description": "When true, recursively deletes all documents (sent to trash) and sub-folders within the folder. Limited to 100 total items (documents + sub-folders)." - }, - "required": false, - "description": "When true, recursively deletes all documents (sent to trash) and sub-folders within the folder. Limited to 100 total items (documents + sub-folders).", - "name": "force", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Folder deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersDeleteResponse" - } - } - } - }, - "400": { - "description": "Folder cannot be deleted (e.g., contains documents or sub-folders and force is not set, or force delete exceeds the 100-item limit)" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - cannot view or delete folder" - }, - "404": { - "description": "Folder not found" - } - } - }, - "patch": { - "description": "Update a folder's display name and/or URL path segment. At least one of `name` or `path` must be provided. Changing the name does not automatically update the path. When the path is updated, descendant folder paths are cascaded.", - "operationId": "foldersUpdate", - "summary": "Update a folder", - "tags": [ - "Folders" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the folder", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Unique identifier for the folder", - "name": "folderId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Folder updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body (empty name, invalid path characters, reserved path, or neither field provided)" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - EDITOR role required" - }, - "404": { - "description": "Folder not found" - }, - "409": { - "description": "Path conflicts with an existing folder (when resolvePathConflict is false)" - } - } - } - }, - "/api/v1/folders/{folderId}/permissions": { - "get": { - "operationId": "foldersGetPermissions", - "summary": "Get folder permissions", - "tags": [ - "Folders" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the folder", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Unique identifier for the folder", - "name": "folderId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter permits for a specific user. If omitted, returns all permits (requires MANAGER role)." - }, - "required": false, - "description": "Filter permits for a specific user. If omitted, returns all permits (requires MANAGER role).", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Folder permissions", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersGetPermissionsResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - VIEWER role required to view specific user permissions, MANAGER role required to list all" - }, - "404": { - "description": "Folder or user not found" - } - } - }, - "post": { - "operationId": "foldersAddPermissions", - "summary": "Add folder permissions", - "tags": [ - "Folders" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the folder", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Unique identifier for the folder", - "name": "folderId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersAddPermissionsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Permissions added successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersAddPermissionsResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - userIds or userGroupIds must be provided" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - MANAGER role required" - }, - "404": { - "description": "Folder not found" - } - } - }, - "patch": { - "operationId": "foldersUpdatePermissions", - "summary": "Update folder permissions", - "tags": [ - "Folders" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the folder", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Unique identifier for the folder", - "name": "folderId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersUpdatePermissionsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Permissions updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersUpdatePermissionsResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - userIds or userGroupIds must be provided" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - MANAGER role required" - }, - "404": { - "description": "Folder not found" - } - } - }, - "delete": { - "operationId": "foldersRevokePermissions", - "summary": "Revoke folder permissions", - "tags": [ - "Folders" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the folder", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Unique identifier for the folder", - "name": "folderId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersRevokePermissionsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Permissions revoked successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FoldersRevokePermissionsResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - userIds or userGroupIds must be provided" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - MANAGER role required" - }, - "404": { - "description": "Folder not found" - } - } - } - }, - "/api/v1/labels": { - "get": { - "operationId": "labelsList", - "summary": "List all labels", - "tags": [ - "Labels" - ], - "responses": { - "200": { - "description": "List of all labels in the organization", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LabelsListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - } - } - }, - "post": { - "operationId": "labelsCreate", - "summary": "Create a label", - "tags": [ - "Labels" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LabelsCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Label created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LabelsCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - cannot create verified/homepage labels without admin permissions" - }, - "409": { - "description": "Label with this name already exists" - } - } - } - }, - "/api/v1/labels/{name}": { - "get": { - "operationId": "labelsGet", - "summary": "Get a label by name", - "tags": [ - "Labels" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "required": true, - "description": "Label name", - "name": "name", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Label details", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LabelsGetResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "404": { - "description": "Label not found" - } - } - }, - "put": { - "operationId": "labelsUpdate", - "summary": "Update a label", - "tags": [ - "Labels" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "required": true, - "description": "Label name", - "name": "name", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LabelsUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Label updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LabelsUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - cannot modify verified/homepage labels without admin permissions" - }, - "404": { - "description": "Label not found" - }, - "409": { - "description": "Label with new name already exists" - } - } - }, - "delete": { - "operationId": "labelsDelete", - "summary": "Delete a label", - "tags": [ - "Labels" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "required": true, - "description": "Label name", - "name": "name", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "204": { - "description": "Label deleted successfully" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - cannot delete verified/homepage labels without admin permissions" - }, - "404": { - "description": "Label not found" - }, - "409": { - "description": "Cannot delete label that is applied to documents" - } - } - } - }, - "/api/v1/models/{modelId}/suggestions": { - "get": { - "description": "Lists AI-generated model suggestions for a shared model, filtered by dismissal status. Requires organization admin permissions.", - "operationId": "modelSuggestionsList", - "summary": "List model suggestions", - "tags": [ - "AI Model Suggestions" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "UUID of the shared model the suggestions belong to", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "required": true, - "description": "UUID of the shared model the suggestions belong to", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Cursor for pagination: the `nextCursor` from the previous response (the last suggestion id)." - }, - "required": false, - "description": "Cursor for pagination: the `nextCursor` from the previous response (the last suggestion id).", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "active", - "ignored", - "all" - ], - "default": "active", - "description": "Which suggestions to return: `active` (default, not dismissed), `ignored` (dismissed only), or `all`.", - "example": "active" - }, - "required": false, - "description": "Which suggestions to return: `active` (default, not dismissed), `ignored` (dismissed only), or `all`.", - "name": "status", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Paginated list of suggestions", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelSuggestionsListResponse" - } - } - } - }, - "400": { - "description": "Invalid query parameters or malformed `modelId`" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" - }, - "404": { - "description": "Model not found in this organization" - } - } - } - }, - "/api/v1/models/{modelId}/suggestions/schedule": { - "put": { - "description": "Enables the daily schedule that generates suggestions for the shared model. Idempotent \u2014 re-enabling leaves an existing schedule untouched. Requires organization admin permissions.", - "operationId": "modelSuggestionsScheduleEnable", - "summary": "Enable the suggestion schedule", - "tags": [ - "AI Model Suggestions" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "UUID of the shared model the suggestions belong to", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "required": true, - "description": "UUID of the shared model the suggestions belong to", - "name": "modelId", - "in": "path" - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScheduleSuggestionsBody" - } - } - } - }, - "responses": { - "200": { - "description": "The schedule is enabled", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScheduleSuggestionsResponse" - } - } - } - }, - "400": { - "description": "Invalid timezone or malformed `modelId`" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" - }, - "404": { - "description": "Model not found in this organization" - }, - "405": { - "description": "Method not allowed" - } - } - }, - "delete": { - "description": "Disables the daily generation schedule for the shared model. Idempotent. Requires organization admin permissions.", - "operationId": "modelSuggestionsScheduleDisable", - "summary": "Disable the suggestion schedule", - "tags": [ - "AI Model Suggestions" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "UUID of the shared model the suggestions belong to", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "required": true, - "description": "UUID of the shared model the suggestions belong to", - "name": "modelId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "The schedule is disabled", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Malformed `modelId`" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" - }, - "404": { - "description": "Model not found in this organization" - }, - "405": { - "description": "Method not allowed" - } - } - } - }, - "/api/v1/models/{modelId}/suggestions/{suggestionId}/ignore": { - "post": { - "description": "Dismisses (ignores) a suggestion, optionally with a reason. Requires organization admin permissions.", - "operationId": "modelSuggestionsIgnore", - "summary": "Ignore a suggestion", - "tags": [ - "AI Model Suggestions" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "UUID of the shared model the suggestion belongs to", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "required": true, - "description": "UUID of the shared model the suggestion belongs to", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "UUID of the suggestion", - "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" - }, - "required": true, - "description": "UUID of the suggestion", - "name": "suggestionId", - "in": "path" - } - ], - "requestBody": { - "required": false, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IgnoreSuggestionBody" - } - } - } - }, - "responses": { - "200": { - "description": "The suggestion was dismissed", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid body or malformed id" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" - }, - "404": { - "description": "Suggestion or model not found in this organization" - }, - "405": { - "description": "Method not allowed" - } - } - } - }, - "/api/v1/models/{modelId}/suggestions/{suggestionId}/restore": { - "post": { - "description": "Restores a previously dismissed suggestion back to the active list. Requires organization admin permissions.", - "operationId": "modelSuggestionsRestore", - "summary": "Restore a suggestion", - "tags": [ - "AI Model Suggestions" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "UUID of the shared model the suggestion belongs to", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "required": true, - "description": "UUID of the shared model the suggestion belongs to", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "UUID of the suggestion", - "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" - }, - "required": true, - "description": "UUID of the suggestion", - "name": "suggestionId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "The suggestion was restored", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Malformed id" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" - }, - "404": { - "description": "Suggestion or model not found in this organization" - }, - "405": { - "description": "Method not allowed" - } - } - } - }, - "/api/v1/models/{modelId}/suggestions/{suggestionId}": { - "delete": { - "description": "Permanently deletes a suggestion. Requires organization admin permissions.", - "operationId": "modelSuggestionsDelete", - "summary": "Delete a suggestion", - "tags": [ - "AI Model Suggestions" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "UUID of the shared model the suggestion belongs to", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "required": true, - "description": "UUID of the shared model the suggestion belongs to", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "UUID of the suggestion", - "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" - }, - "required": true, - "description": "UUID of the suggestion", - "name": "suggestionId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "The suggestion was deleted", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Malformed id" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" - }, - "404": { - "description": "Suggestion or model not found in this organization" - }, - "405": { - "description": "Method not allowed" - } - } - } - }, - "/api/v1/models": { - "get": { - "operationId": "modelsList", - "summary": "List models", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by base model ID" - }, - "required": false, - "description": "Filter by base model ID", - "name": "baseModelId", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by connection ID" - }, - "required": false, - "description": "Filter by connection ID", - "name": "connectionId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination" - }, - "required": false, - "description": "Cursor for pagination", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of fields to include (e.g., activeBranches)", - "example": "activeBranches" - }, - "required": false, - "description": "Comma-separated list of fields to include (e.g., activeBranches)", - "name": "include", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "0", - "1", - "true", - "false" - ], - "description": "Include deleted models" - }, - "required": false, - "description": "Include deleted models", - "name": "includeDeleted", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by specific model ID" - }, - "required": false, - "description": "Filter by specific model ID", - "name": "modelId", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "SCHEMA", - "SHARED", - "SHARED_EXTENSION", - "BRANCH", - "WORKBOOK", - "QUERY" - ], - "description": "Filter by model kind" - }, - "required": false, - "description": "Filter by model kind", - "name": "modelKind", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by model name" - }, - "required": false, - "description": "Filter by model name", - "name": "name", - "in": "query" - }, - { - "schema": { - "type": "integer", - "exclusiveMinimum": 0, - "description": "Number of results per page", - "example": 20 - }, - "required": false, - "description": "Number of results per page", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "description": "Sort direction" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name", - "modelKind", - "connectionId", - "baseModelId", - "createdAt", - "updatedAt" - ], - "description": "Field to sort by" - }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Paginated list of models", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - } - } - }, - "post": { - "description": "Create a new model. Supports creating schema, shared, branch, and shared_extension models.", - "operationId": "modelsCreate", - "summary": "Create model", - "tags": [ - "Models" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateModelSchemaBase" - } - } - } - }, - "responses": { - "200": { - "description": "Model created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "error": { - "type": "string", - "description": "Error message if creation failed" - }, - "message": { - "type": "string", - "description": "Additional message" - }, - "model": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Created model ID" - }, - "modelKind": { - "type": "string", - "description": "Kind of model created" - }, - "name": { - "type": [ - "string", - "null" - ], - "description": "Model name" - } - }, - "required": [ - "id", - "modelKind", - "name" - ], - "description": "Created model details" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - } - }, - "required": [ - "success" - ], - "description": "Create model response", - "title": "ModelsCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or model creation not allowed" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Connection or base model not found" - } - } - } - }, - "/api/v1/models/{modelId}": { - "patch": { - "description": "Update metadata for an existing model. Currently supports renaming the model via the `name` field.", - "operationId": "modelsUpdate", - "summary": "Update model", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Model updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found" - } - } - } - }, - "/api/v1/jobs/{jobId}/status": { - "get": { - "description": "Check status of a schema refresh job (POST /api/v1/models/{modelId}/refresh) or a dbt sync job (POST /api/v1/models/{modelId}/dbt-sync). Returns IN_PROGRESS, COMPLETED, or FAILED.", - "operationId": "jobsGetStatus", - "summary": "Get schema refresh or dbt sync job status", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "The job ID returned from a job creation endpoint (e.g., POST /api/v1/models/{modelId}/refresh)", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "The job ID returned from a job creation endpoint (e.g., POST /api/v1/models/{modelId}/refresh)", - "name": "jobId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Job status (IN_PROGRESS, COMPLETED, or FAILED)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/JobsGetStatusResponse" - } - } - } - }, - "400": { - "description": "Unsupported job type (only schema refresh and dbt sync supported)" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection READ permission required" - }, - "404": { - "description": "Job not found" - } - } - } - }, - "/api/v1/models/{modelId}/schemas": { - "get": { - "operationId": "modelsGetSchemas", - "summary": "List available schemas for a model", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID to use for branch-aware operations", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "required": false, - "description": "Branch ID to use for branch-aware operations", - "name": "branch_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of available schemas", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsGetSchemasResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found" - } - } - } - }, - "/api/v1/models/{modelId}/view": { - "get": { - "operationId": "modelsGetViews", - "summary": "Get model views", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID to use for branch-aware operations", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "required": false, - "description": "Branch ID to use for branch-aware operations", - "name": "branch_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of views in the model", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsGetViewResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found" - } - } - } - }, - "/api/v1/models/{modelId}/view/{viewName}": { - "patch": { - "operationId": "modelsUpdateView", - "summary": "Update view", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "View name", - "example": "orders" - }, - "required": true, - "description": "View name", - "name": "viewName", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID to use for branch-aware operations", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "required": false, - "description": "Branch ID to use for branch-aware operations", - "name": "branch_id", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsUpdateViewBody" - } - } - } - }, - "responses": { - "200": { - "description": "View updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or view not found" - } - } - }, - "delete": { - "operationId": "modelsDeleteView", - "summary": "Delete view", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "View name", - "example": "orders" - }, - "required": true, - "description": "View name", - "name": "viewName", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID to use for branch-aware operations", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "required": false, - "description": "Branch ID to use for branch-aware operations", - "name": "branch_id", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "COMBINED", - "MERGED", - "EXTENSION" - ], - "description": "Controls delete behavior to match IDE editing modes. COMBINED (default) marks the view as ignored if it exists in the parent model, otherwise hard-deletes. MERGED marks the view as shallowIgnored (hidden only from the immediate parent). EXTENSION hard-deletes the view from the extension layer.", - "example": "COMBINED" - }, - "required": false, - "description": "Controls delete behavior to match IDE editing modes. COMBINED (default) marks the view as ignored if it exists in the parent model, otherwise hard-deletes. MERGED marks the view as shallowIgnored (hidden only from the immediate parent). EXTENSION hard-deletes the view from the extension layer.", - "name": "mode", - "in": "query" - } - ], - "responses": { - "200": { - "description": "View deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or view not found" - } - } - } - }, - "/api/v1/models/{modelId}/view/{viewName}/field/{fieldName}": { - "patch": { - "operationId": "modelsUpdateField", - "summary": "Update field", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "View name", - "example": "orders" - }, - "required": true, - "description": "View name", - "name": "viewName", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Field name", - "example": "total_amount" - }, - "required": true, - "description": "Field name", - "name": "fieldName", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID to use for branch-aware operations", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "required": false, - "description": "Branch ID to use for branch-aware operations", - "name": "branch_id", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsUpdateFieldBody" - } - } - } - }, - "responses": { - "200": { - "description": "Field updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model, view, or field not found" - } - } - }, - "delete": { - "operationId": "modelsDeleteField", - "summary": "Delete field", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "View name", - "example": "orders" - }, - "required": true, - "description": "View name", - "name": "viewName", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Field name", - "example": "total_amount" - }, - "required": true, - "description": "Field name", - "name": "fieldName", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID" - }, - "required": false, - "description": "Branch ID", - "name": "branch_id", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Topic context for the field" - }, - "required": false, - "description": "Topic context for the field", - "name": "topic_context", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Field deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model, view, or field not found" - } - } - } - }, - "/api/v1/models/{modelId}/topic": { - "get": { - "operationId": "modelsListTopics", - "summary": "List topics", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID to use for branch-aware operations", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "required": false, - "description": "Branch ID to use for branch-aware operations", - "name": "branch_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of topics in the model", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsListTopicsResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found" - } - } - } - }, - "/api/v1/models/{modelId}/topic/{topicName}": { - "get": { - "operationId": "modelsGetTopic", - "summary": "Get topic", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Topic name", - "example": "sales_analytics" - }, - "required": true, - "description": "Topic name", - "name": "topicName", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID to use for branch-aware operations", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "required": false, - "description": "Branch ID to use for branch-aware operations", - "name": "branch_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Topic details with relationships and views", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsGetTopicResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or topic not found" - } - } - }, - "patch": { - "operationId": "modelsUpdateTopic", - "summary": "Update topic", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Topic name", - "example": "sales_analytics" - }, - "required": true, - "description": "Topic name", - "name": "topicName", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID to use for branch-aware operations", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "required": false, - "description": "Branch ID to use for branch-aware operations", - "name": "branch_id", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsUpdateTopicBody" - } - } - } - }, - "responses": { - "200": { - "description": "Topic updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or topic not found" - } - } - }, - "delete": { - "operationId": "modelsDeleteTopic", - "summary": "Delete topic", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Topic name", - "example": "sales_analytics" - }, - "required": true, - "description": "Topic name", - "name": "topicName", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID to use for branch-aware operations", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "required": false, - "description": "Branch ID to use for branch-aware operations", - "name": "branch_id", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "COMBINED", - "MERGED", - "EXTENSION" - ], - "description": "Controls delete behavior to match IDE editing modes. COMBINED (default) adds the topic to deletedTopics if it exists in the parent model (prevents reappearing). MERGED behaves the same as COMBINED. EXTENSION hard-deletes the topic from the extension layer.", - "example": "COMBINED" - }, - "required": false, - "description": "Controls delete behavior to match IDE editing modes. COMBINED (default) adds the topic to deletedTopics if it exists in the parent model (prevents reappearing). MERGED behaves the same as COMBINED. EXTENSION hard-deletes the topic from the extension layer.", - "name": "mode", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Topic deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or topic not found" - } - } - } - }, - "/api/v1/models/{modelId}/field": { - "post": { - "operationId": "modelsCreateField", - "summary": "Create field", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsCreateFieldBody" - } - } - } - }, - "responses": { - "201": { - "description": "Field created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or view not found" - } - } - } - }, - "/api/v1/models/{modelId}/refresh": { - "post": { - "operationId": "modelsRefresh", - "summary": "Refresh model schema", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID for branch-based schema refresh. Required when branch-based schema refresh is enabled for the connection. Must not be provided when branch-based schema refresh is not enabled.", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "required": false, - "description": "Branch ID for branch-based schema refresh. Required when branch-based schema refresh is enabled for the connection. Must not be provided when branch-based schema refresh is not enabled.", - "name": "branch_id", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "true", - "false" - ], - "description": "When true (the default), performs a hard refresh that fully discards and rebuilds the schema model. When false, performs a soft refresh that merges newly generated views with the existing model. Must be set to false when `schemas` or `tables` filters are provided.", - "example": "false" - }, - "required": false, - "description": "When true (the default), performs a hard refresh that fully discards and rebuilds the schema model. When false, performs a soft refresh that merges newly generated views with the existing model. Must be set to false when `schemas` or `tables` filters are provided.", - "name": "hard_refresh", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Optional comma-separated list of schemas to refresh selectively. Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", - "example": "public,analytics" - }, - "required": false, - "description": "Optional comma-separated list of schemas to refresh selectively. Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", - "name": "schemas", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Optional comma-separated list of tables to refresh selectively. Only the listed tables are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", - "example": "public.orders,public.customers" - }, - "required": false, - "description": "Optional comma-separated list of tables to refresh selectively. Only the listed tables are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", - "name": "tables", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Refresh job started", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsRefreshResponse" - } - } - } - }, - "400": { - "description": "Bad request - branch_id required when branch-based schema refresh is enabled, branch_id not allowed when it is not enabled, or hard refresh requested with selective schemas/tables filters" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Model not found" - } - } - } - }, - "/api/v1/models/{modelId}/validate": { - "get": { - "operationId": "modelsValidate", - "summary": "Validate model", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID to validate" - }, - "required": false, - "description": "Branch ID to validate", - "name": "branchId", - "in": "query" - }, - { - "schema": { - "type": "integer", - "exclusiveMinimum": 0, - "description": "Maximum number of validation issues to return" - }, - "required": false, - "description": "Maximum number of validation issues to return", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Validation results", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsValidateResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found" - } - } - } - }, - "/api/v1/models/{modelId}/migrate": { - "post": { - "operationId": "modelsMigrate", - "summary": "Migrate model", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsMigrateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Migration completed successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or migration not allowed" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found" - } - } - } - }, - "/api/v1/models/{modelId}/branch/{branchName}": { - "delete": { - "operationId": "modelsDeleteBranch", - "summary": "Delete branch", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Branch name", - "example": "feature/new-metrics" - }, - "required": true, - "description": "Branch name", - "name": "branchName", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Branch deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or branch not found" - } - } - } - }, - "/api/v1/models/{modelId}/dbt-exposures": { - "get": { - "description": "Returns the dbt exposures for a model, computed on-demand by analyzing which dbt models are referenced by dashboards that use this model. Returns exactly one record per dashboard. The exposure field is null when a dashboard does not reference any dbt models. Exposure names (exposure.name) may contain duplicates when multiple dashboards produce the same name; use deduplication_name for a guaranteed-unique value, or use it as a fallback when names collide.", - "operationId": "modelsDbtExposures", - "summary": "Get dbt exposures", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Field to sort results by" - }, - "required": false, - "description": "Field to sort results by", - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID to use for branch-aware operations", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "required": false, - "description": "Branch ID to use for branch-aware operations", - "name": "branch_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of dbt exposures for the model", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsDbtExposuresResponse" - } - } - } - }, - "400": { - "description": "Invalid request parameters" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found" - } - } - } - }, - "/api/v1/models/{modelId}/branch/{branchName}/dbt": { - "post": { - "description": "Set the active dbt environment on a branch.", - "operationId": "modelsBranchDbt", - "summary": "Set branch dbt environment", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Branch name", - "example": "feature/new-metrics" - }, - "required": true, - "description": "Branch name", - "name": "branchName", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsBranchDbtBody" - } - } - } - }, - "responses": { - "200": { - "description": "dbt environment set successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or branch not found" - } - } - } - }, - "/api/v1/models/{modelId}/dbt-sync": { - "post": { - "description": "Trigger a dbt metadata sync (\"dbt quick sync\") for a branch. Recompiles the branch's dbt manifest and merges the regenerated dbt extension model, without a full database schema scan. The branch (via branch_id) supplies the dbt environment and dbt git branch. Runs as a background job.", - "operationId": "modelsDbtSync", - "summary": "Trigger a dbt metadata sync for a branch", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "ID of the branch to sync dbt metadata for. The branch supplies the dbt environment and dbt git branch to compile against (set via POST /api/v1/models/{modelId}/branch/{branchName}/dbt).", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "required": true, - "description": "ID of the branch to sync dbt metadata for. The branch supplies the dbt environment and dbt git branch to compile against (set via POST /api/v1/models/{modelId}/branch/{branchName}/dbt).", - "name": "branch_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "dbt sync job started", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/JobCreatedResponse" - } - } - } - }, - "400": { - "description": "Invalid request parameters" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or branch not found, or model deleted" - }, - "405": { - "description": "Method not allowed" - }, - "422": { - "description": "The model is not a shared model" - } - } - } - }, - "/api/v1/models/{modelId}/branch/{branchName}/merge": { - "post": { - "operationId": "modelsMergeBranch", - "summary": "Merge branch", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Branch name", - "example": "feature/new-metrics" - }, - "required": true, - "description": "Branch name", - "name": "branchName", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsMergeBranchBody" - } - } - } - }, - "responses": { - "200": { - "description": "Branch merged successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsMergeBranchResponse" - } - } - } - }, - "400": { - "description": "Invalid request body, merge not allowed, or merge conflict" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied or PR required" - }, - "404": { - "description": "Model or branch not found" - } - } - } - }, - "/api/v1/models/{modelId}/git/commit": { - "post": { - "description": "Push the branch contents to git and create or update a pull request. The backend automatically detects whether the git branch already exists: if not, it creates a new git branch and opens a PR; if it does, it commits the latest model contents to the existing branch (updating the open PR).", - "operationId": "modelsCommit", - "summary": "Commit branch to git", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsCommitBody" - } - } - } - }, - "responses": { - "200": { - "description": "Branch committed to git and pull request created or updated", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsCommitResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied or git not configured" - }, - "404": { - "description": "Model or branch not found" - } - } - } - }, - "/api/v1/models/{modelId}/cache_reset/{policyName}": { - "post": { - "operationId": "modelsCacheReset", - "summary": "Reset cache for policy", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Cache policy name", - "example": "daily_refresh" - }, - "required": true, - "description": "Cache policy name", - "name": "policyName", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsCacheResetBody" - } - } - } - }, - "responses": { - "200": { - "description": "Cache reset scheduled", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsCacheResetResponse" - } - } - } - }, - "400": { - "description": "Invalid reset timestamp" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or cache policy not found" - } - } - } - }, - "/api/v1/models/{modelId}/git": { - "get": { - "operationId": "modelsGitGet", - "summary": "Get git configuration", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of optional fields to include. Supported: \"webhookSecret\"", - "example": "webhookSecret" - }, - "required": false, - "description": "Comma-separated list of optional fields to include. Supported: \"webhookSecret\"", - "name": "include", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Git configuration for the model", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsGitGetResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found or git not configured" - } - } - }, - "post": { - "operationId": "modelsGitCreate", - "summary": "Create git configuration", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsGitCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Git configuration created", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsGitCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid SSH URL or configuration" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found" - }, - "409": { - "description": "Git already configured for this model" - } - } - }, - "patch": { - "operationId": "modelsGitUpdate", - "summary": "Update git configuration", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsGitUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Git configuration updated", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsGitUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid SSH URL or configuration" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found or git not configured" - } - } - }, - "delete": { - "operationId": "modelsGitDelete", - "summary": "Delete git configuration", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Git configuration deleted", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsGitDeleteResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found or git not configured" - } - } - } - }, - "/api/v1/models/{modelId}/git/sync": { - "post": { - "operationId": "modelsGitSync", - "summary": "Sync model with git", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsGitSyncBody" - } - } - } - }, - "responses": { - "200": { - "description": "Sync status and result (includes inSync=false for conflicts requiring manual resolution)", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsGitSyncResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied or git not configured" - }, - "404": { - "description": "Model not found" - } - } - } - }, - "/api/v1/models/{modelId}/content-validator": { - "get": { - "operationId": "modelsContentValidatorGet", - "summary": "Validate content references", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Optional branch ID to validate against. Non-UUID values return 400." - }, - "required": false, - "description": "Optional branch ID to validate against. Non-UUID values return 400.", - "name": "branch_id", - "in": "query" - }, - { - "schema": { - "$ref": "#/components/schemas/ContentFilterMode" - }, - "required": false, - "description": "Filter documents by issue status. ALL (default) returns all documents with at least one query. WITH_ISSUES returns only documents with at least one query issue, dashboard filter issue, or document error. NO_ISSUES returns only documents with zero issues and no document errors.", - "name": "content_filter_mode", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter to documents created by this user (user ID). Unknown IDs return 400." - }, - "required": false, - "description": "Filter to documents created by this user (user ID). Unknown IDs return 400.", - "name": "creator_id", - "in": "query" - }, - { - "schema": { - "type": "string", - "minLength": 1, - "description": "Optional value to find. Used with find_type to scope validation to a single view, field, or topic. Requires find_type to be provided." - }, - "required": false, - "description": "Optional value to find. Used with find_type to scope validation to a single view, field, or topic. Requires find_type to be provided.", - "name": "find", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "FIELD", - "TOPIC", - "VIEW" - ], - "description": "Optional type of find operation (VIEW, FIELD, TOPIC). Requires find to be provided. FIELD values must be scoped by view name (e.g. view_name.field_name)." - }, - "required": false, - "description": "Optional type of find operation (VIEW, FIELD, TOPIC). Requires find to be provided. FIELD values must be scoped by view name (e.g. view_name.field_name).", - "name": "find_type", - "in": "query" - }, - { - "schema": { - "type": "array", - "description": "Prefix-match folder paths. \"/Finance\" matches \"/Finance/Reports\". Documents with no folder are excluded unless \"\" is specified.", - "items": { - "type": "string" - } - }, - "required": false, - "description": "Prefix-match folder paths. \"/Finance\" matches \"/Finance/Reports\". Documents with no folder are excluded unless \"\" is specified.", - "name": "folder_paths", - "in": "query" - }, - { - "schema": { - "type": "boolean", - "description": "Whether to include personal folders in validation" - }, - "required": false, - "description": "Whether to include personal folders in validation", - "name": "include_personal_folders", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated label names. Documents matching any label are included. Unknown labels return 400." - }, - "required": false, - "description": "Comma-separated label names. Documents matching any label are included. Unknown labels return 400.", - "name": "labels", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Optional user ID for scoping" - }, - "required": false, - "description": "Optional user ID for scoping", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Content validation results", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsContentValidatorGetResponse" - } - } - } - }, - "400": { - "description": "Invalid parameters or unknown labels" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found" - } - } - }, - "post": { - "operationId": "modelsContentValidatorReplace", - "summary": "Replace content references", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsContentValidatorReplaceBody" - } - } - } - }, - "responses": { - "200": { - "description": "Replace operation completed", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelsContentValidatorReplaceResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found" - } - } - } - }, - "/api/v1/models/{modelId}/yaml": { - "get": { - "operationId": "modelsYamlGet", - "summary": "Get model YAML", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID for branch-aware operations" - }, - "required": false, - "description": "Branch ID for branch-aware operations", - "name": "branchId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "File name to operate on" - }, - "required": false, - "description": "File name to operate on", - "name": "fileName", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "combined", - "extension", - "staged", - "merged", - "fully-resolved" - ], - "default": "combined", - "description": "IDE mode for YAML operations" - }, - "required": false, - "description": "IDE mode for YAML operations", - "name": "mode", - "in": "query" - }, - { - "schema": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "boolean" - } - ], - "default": false, - "description": "Resolve the model extends chain so the returned YAML reflects what runs at query time. Only valid with mode=combined." - }, - "required": false, - "description": "Resolve the model extends chain so the returned YAML reflects what runs at query time. Only valid with mode=combined.", - "name": "fullyResolved", - "in": "query" - }, - { - "schema": { - "type": [ - "boolean", - "null" - ], - "default": false, - "description": "Include checksums in response" - }, - "required": false, - "description": "Include checksums in response", - "name": "includeChecksums", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "A single schema name (optionally catalog-scoped, e.g. 'warehouse.reporting') to additionally load into the response. Use this to include view YAML from a schema that isn't active in the model (inactive or offloaded). Only views from this schema will be returned (views with no schema are always included)." - }, - "required": false, - "description": "A single schema name (optionally catalog-scoped, e.g. 'warehouse.reporting') to additionally load into the response. Use this to include view YAML from a schema that isn't active in the model (inactive or offloaded). Only views from this schema will be returned (views with no schema are always included).", - "name": "includeSchemas", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Model YAML content", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelYamlResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found" - } - } - }, - "post": { - "operationId": "modelsYamlCreate", - "summary": "Update model YAML", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelYamlCreateRequestBody" - } - } - } - }, - "responses": { - "200": { - "description": "Model YAML updated", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ModelYamlResponse" - } - } - } - }, - "400": { - "description": "Invalid YAML or file name" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found" - }, - "409": { - "description": "Checksum mismatch (concurrent modification)" - } - } - }, - "delete": { - "operationId": "modelsYamlDelete", - "summary": "Delete model YAML file", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Branch ID for branch-aware operations" - }, - "required": false, - "description": "Branch ID for branch-aware operations", - "name": "branchId", - "in": "query" - }, - { - "schema": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "string" - } - ], - "description": "File name to delete (must end with '.topic' or '.view')" - }, - "required": true, - "description": "File name to delete (must end with '.topic' or '.view')", - "name": "fileName", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "combined", - "extension", - "staged", - "merged", - "fully-resolved" - ], - "default": "combined", - "description": "IDE mode for YAML operations" - }, - "required": false, - "description": "IDE mode for YAML operations", - "name": "mode", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Commit message for git sync" - }, - "required": false, - "description": "Commit message for git sync", - "name": "commitMessage", - "in": "query" - } - ], - "responses": { - "200": { - "description": "YAML file deleted" - }, - "400": { - "description": "Invalid file name" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or file not found" - } - } - } - }, - "/api/v1/models/{modelId}/ai-agent-actions": { - "get": { - "description": "Returns the AI agent actions configured for this model \u2014 a unified list of sample queries and skills suitable for surfacing as suggested prompts above an AI prompt input. Sample queries come from both `model.sample_queries` and each topic's `sample_queries`; skills come from `model.skills` and each topic's `skills`, deduped by id with topic skills overriding model skills. Each entry's `prompt` is ready to submit verbatim to `POST /api/v1/ai/jobs`.", - "operationId": "modelAiAgentActions", - "summary": "Get model AI agent actions", - "tags": [ - "Models" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Model UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Model UUID", - "name": "modelId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "AI agent actions in display order.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiAgentActionsResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid API key." - }, - "403": { - "description": "Caller cannot read the model." - }, - "404": { - "description": "Model not found." - } - } - } - }, - "/api/v1/query/run": { - "post": { - "operationId": "queryRun", - "summary": "Execute a semantic query", - "tags": [ - "Query" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryRunBody" - } - } - } - }, - "responses": { - "200": { - "description": "Query executed or started successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryRunResponse" - } - } - } - }, - "400": { - "description": "Invalid query definition or conflicting parameters" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - querier role required on the model" - }, - "404": { - "description": "Model, topic, view, or branch not found" - }, - "408": { - "description": "Query timed out. The response includes remaining_job_ids that can be polled via the query/wait endpoint.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryTimeoutResponse" - } - } - } - }, - "500": { - "description": "Query execution error" - } - } - } - }, - "/api/v1/query/wait": { - "get": { - "operationId": "queryWait", - "summary": "Wait for query jobs to complete", - "tags": [ - "Query" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Comma-separated list of job IDs to wait for. Obtained from the query/run response.", - "example": "job_abc123,job_def456" - }, - "required": true, - "description": "Comma-separated list of job IDs to wait for. Obtained from the query/run response.", - "name": "jobIds", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Query results for completed jobs", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QueryWaitResponse" - } - } - } - }, - "400": { - "description": "Invalid or missing jobIds parameter" - }, - "401": { - "description": "Authentication required" - }, - "404": { - "description": "Job ID not found" - }, - "500": { - "description": "Error fetching query results" - } - } - } - }, - "/api/v1/schedules": { - "get": { - "operationId": "schedulesList", - "summary": "List schedules", - "tags": [ - "Schedules" - ], - "parameters": [ - { - "schema": { - "type": "string", - "minLength": 1, - "default": 1, - "description": "The page number for offset-based pagination.", - "example": 1 - }, - "required": false, - "description": "The page number for offset-based pagination.", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "The direction to sort results (asc or desc).", - "example": "desc" - }, - "required": false, - "description": "The direction to sort results (asc or desc).", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "scheduleName", - "dashboardName", - "ownerName", - "lastRun", - "lastRunStatus" - ], - "default": "scheduleName", - "description": "The field to sort results by. Valid values: scheduleName, dashboardName, ownerName, lastRun, lastRunStatus.", - "example": "scheduleName" - }, - "required": false, - "description": "The field to sort results by. Valid values: scheduleName, dashboardName, ownerName, lastRun, lastRunStatus.", - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "dashboard", - "single tile" - ], - "description": "Filter schedules by content type: dashboard, single tile.", - "example": "dashboard" - }, - "required": false, - "description": "Filter schedules by content type: dashboard, single tile.", - "name": "contentType", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter schedules by embed entity." - }, - "required": false, - "description": "Filter schedules by embed entity.", - "name": "embedEntity", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "email", - "google_sheets", - "s3", - "sftp", - "slack", - "webhook" - ], - "description": "Filter schedules by destination type: email, slack, webhook, sftp, s3.", - "example": "email" - }, - "required": false, - "description": "Filter schedules by destination type: email, slack, webhook, sftp, s3.", - "name": "destination", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter schedules by the document's unique identifier. Can be found in the dashboard's URL after /dashboards/.", - "example": "12db1a0a" - }, - "required": false, - "description": "Filter schedules by the document's unique identifier. Can be found in the dashboard's URL after /dashboards/.", - "name": "identifier", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter schedules by the owner's user ID. Use the List users endpoint to retrieve user IDs.", - "example": "987fcdeb-51a2-43d7-9b56-254415f67890" - }, - "required": false, - "description": "Filter schedules by the owner's user ID. Use the List users endpoint to retrieve user IDs.", - "name": "ownerId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Search term for filtering schedules by name, dashboard name, or owner name (case-insensitive).", - "example": "Weekly" - }, - "required": false, - "description": "Search term for filtering schedules by name, dashboard name, or owner name (case-insensitive).", - "name": "q", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "alert", - "schedule" - ], - "description": "Filter by type: alert, schedule.", - "example": "schedule" - }, - "required": false, - "description": "Filter by type: alert, schedule.", - "name": "scheduleType", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "success", - "error", - "canceled", - "none" - ], - "description": "Filter schedules by delivery status: success, error, canceled, none.", - "example": "success" - }, - "required": false, - "description": "Filter schedules by delivery status: success, error, canceled, none.", - "name": "status", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Paginated list of schedules", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchedulesListItem" - } - } - }, - "required": [ - "pageInfo", - "records" - ] - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - } - } - }, - "post": { - "description": "Create a new scheduled delivery for a dashboard. Required fields vary by destinationType (email, webhook, sftp, slack). For org API keys, use the userId query parameter to create the schedule on behalf of a specific user.", - "operationId": "schedulesCreate", - "summary": "Create schedule", - "tags": [ - "Schedules" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Membership ID of the user who should own the schedule (org API keys only). If not provided, the schedule is owned by the API key owner. User-scoped API keys cannot use this parameter.", - "example": "987fcdeb-51a2-43d7-9b56-254415f67890" - }, - "required": false, - "description": "Membership ID of the user who should own the schedule (org API keys only). If not provided, the schedule is owned by the API key owner. User-scoped API keys cannot use this parameter.", - "name": "userId", - "in": "query" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "bucketName": { - "type": "string", - "description": "S3 bucket name (S3 destination only). Must be 3-63 characters, lowercase.", - "example": "my-reports-bucket" - }, - "conditionQueryMapKey": { - "type": "string", - "description": "The ID of the query to monitor for triggering an alert. Required if conditionType is provided.", - "example": "Jmn2r3KV" - }, - "conditionType": { - "type": "string", - "enum": [ - "RESULTS_CHANGED", - "RESULTS_UNCHANGED", - "RESULTS_PRESENT", - "RESULTS_MISSING" - ], - "description": "Defines the type of condition to use for alerts. Required if conditionQueryMapKey is provided.", - "example": "RESULTS_PRESENT" - }, - "destinationType": { - "type": "string", - "enum": [ - "email", - "webhook", - "sftp", - "slack", - "s3" - ], - "description": "The delivery destination type", - "example": "email" - }, - "enableFormatting": { - "type": "boolean", - "description": "If true, formatting will be enabled in the output", - "example": false - }, - "fanOut": { - "type": "boolean", - "description": "If true, send personalized emails to each recipient (email only)", - "example": false - }, - "filterConfig": { - "description": "Filter conditions to apply to the task", - "example": { - "status": [ - "active", - "pending" - ] - } - }, - "format": { - "type": "string", - "enum": [ - "link_only", - "pdf", - "png", - "csv", - "xlsx", - "json" - ], - "description": "The output format: link_only, pdf, png, csv, xlsx, json", - "example": "pdf" - }, - "hideHiddenFields": { - "type": "boolean", - "description": "If true, hidden fields won't be displayed (csv/xlsx only)", - "example": false - }, - "hideTitle": { - "type": "boolean", - "description": "If true, hide the title in output (pdf/png only)", - "example": false - }, - "identifier": { - "type": "string", - "description": "The ID of the dashboard to schedule", - "example": "12db1a0a" - }, - "keyPrefix": { - "type": "string", - "description": "S3 key prefix / folder path (S3 destination only). Leading slashes are normalized.", - "example": "reports/weekly/" - }, - "killJobsOnFailure": { - "type": "boolean", - "description": "If true, stop entire job if any queries fail", - "example": false - }, - "name": { - "type": "string", - "description": "The name of the scheduled task", - "example": "Weekly Sales Report" - }, - "recipients": { - "type": "array", - "items": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Recipient email address", - "example": "user@example.com" - } - }, - "required": [ - "email" - ] - }, - "description": "Email recipients (email destination only). For Slack destinations, use the \"recipients\" field with a channel ID string or user ID(s) as a string or array." - }, - "region": { - "type": "string", - "description": "AWS region where the S3 bucket is located (S3 destination only).", - "example": "us-east-1" - }, - "roleArn": { - "type": "string", - "description": "ARN of the cross-account IAM role Omni will assume to write to the S3 bucket (S3 destination only).", - "example": "arn:aws:iam::123456789012:role/OmniS3DeliveryRole" - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", - "example": "0 9 ? * MON *" - }, - "showContentLink": { - "type": "boolean", - "description": "If true, include a link to the content", - "example": true - }, - "showFilters": { - "type": "boolean", - "description": "If true, show applied filters in output", - "example": true - }, - "slackRecipientType": { - "type": "string", - "description": "Slack recipient type (Slack destination only). Use \"channel\" to deliver to a single Slack channel, or \"users\" to deliver to one or more Slack users via direct message.", - "example": "channel" - }, - "testNow": { - "type": "boolean", - "description": "If true, run immediately instead of scheduling", - "example": false - }, - "timezone": { - "type": "string", - "description": "IANA timezone for the schedule", - "example": "America/New_York" - }, - "timezoneOverride": { - "type": [ - "string", - "null" - ], - "description": "Optional IANA timezone applied to query execution at render time. Distinct from `timezone` (which controls *when* the schedule fires). Omit or pass null for no override.", - "example": "Europe/Paris" - }, - "webhookUrl": { - "type": "string", - "format": "uri", - "description": "Webhook URL (webhook destination only)", - "example": "https://example.com/webhook" - } - }, - "required": [ - "destinationType", - "format", - "identifier", - "name", - "schedule", - "timezone" - ], - "description": "Request body for creating a scheduled task. Required fields vary by destinationType.", - "title": "SchedulesCreateBody" - } - } - } - }, - "responses": { - "200": { - "description": "Schedule created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "delivererRoleArn": { - "type": "string", - "description": "The ARN of the Omni deliverer role. Use this as the Principal in your IAM role trust policy. Only returned for S3 destinations.", - "example": "arn:aws:iam::529831494235:role/OmniSchedulerDelivererRole" - }, - "externalId": { - "type": "string", - "format": "uuid", - "description": "The organization ID used as the external ID for confused deputy prevention. Add this to your IAM role trust policy as the sts:ExternalId condition. Static across all S3 destinations for your organization. Only returned for S3 destinations.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Created schedule ID (only when testNow is false)", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "message": { - "type": "string", - "description": "Success message", - "example": "Successfully created schedule" - } - }, - "required": [ - "message" - ], - "description": "Create schedule response", - "title": "SchedulesCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or filter configuration" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - cannot schedule this dashboard" - }, - "404": { - "description": "Dashboard not found" - } - } - } - }, - "/api/v1/schedules/{scheduleId}": { - "get": { - "operationId": "schedulesGet", - "summary": "Get schedule", - "tags": [ - "Schedules" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "name": "scheduleId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Membership ID of the user whose access should be checked (org API keys only). When provided, the endpoint checks if that user has permission to view the schedule. User-scoped API keys cannot use this parameter.", - "example": "987fcdeb-51a2-43d7-9b56-254415f67890" - }, - "required": false, - "description": "Membership ID of the user whose access should be checked (org API keys only). When provided, the endpoint checks if that user has permission to view the schedule. User-scoped API keys cannot use this parameter.", - "name": "userId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Schedule details", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SchedulesGetResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - must be schedule owner or have manage permission" - }, - "404": { - "description": "Schedule not found" - } - } - }, - "put": { - "operationId": "schedulesUpdate", - "summary": "Update schedule", - "tags": [ - "Schedules" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "name": "scheduleId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Schedule updated successfully" - }, - "400": { - "description": "Invalid request body or filter configuration" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - must be schedule owner or have manage permission" - }, - "404": { - "description": "Schedule or dashboard not found" - } - } - }, - "delete": { - "operationId": "schedulesDelete", - "summary": "Delete schedule", - "tags": [ - "Schedules" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "name": "scheduleId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Schedule deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - must be schedule owner or have manage permission" - }, - "404": { - "description": "Schedule not found" - } - } - } - }, - "/api/v1/schedules/{scheduleId}/recipients": { - "get": { - "operationId": "schedulesRecipientsGet", - "summary": "Get schedule recipients", - "tags": [ - "Schedules" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "name": "scheduleId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Schedule recipients", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SchedulesRecipientsGetResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Schedule not found" - } - } - } - }, - "/api/v1/schedules/{scheduleId}/add-recipients": { - "put": { - "operationId": "schedulesAddRecipients", - "summary": "Add schedule recipients", - "tags": [ - "Schedules" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "name": "scheduleId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SchedulesAddRecipientsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Recipients added successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SchedulesAddRecipientsResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - at least one email, userId, or userGroupId required" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Schedule not found" - } - } - } - }, - "/api/v1/schedules/{scheduleId}/remove-recipients": { - "put": { - "operationId": "schedulesRemoveRecipients", - "summary": "Remove schedule recipients", - "tags": [ - "Schedules" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "name": "scheduleId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SchedulesRemoveRecipientsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Recipients removed successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SchedulesRemoveRecipientsResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - at least one email, userId, or userGroupId required" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Schedule not found" - } - } - } - }, - "/api/v1/schedules/{scheduleId}/pause": { - "put": { - "operationId": "schedulesPause", - "summary": "Pause schedule", - "tags": [ - "Schedules" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "name": "scheduleId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Schedule paused successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Schedule not found" - } - } - } - }, - "/api/v1/schedules/{scheduleId}/resume": { - "put": { - "operationId": "schedulesResume", - "summary": "Resume schedule", - "tags": [ - "Schedules" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "name": "scheduleId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Schedule resumed successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Schedule not found" - } - } - } - }, - "/api/v1/schedules/{scheduleId}/trigger": { - "post": { - "operationId": "schedulesTrigger", - "summary": "Trigger schedule", - "tags": [ - "Schedules" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "name": "scheduleId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Schedule triggered successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Schedule not found" - }, - "409": { - "description": "Schedule cannot be triggered (paused, system-disabled, or another execution is in progress)" - } - } - } - }, - "/api/v1/schedules/{scheduleId}/transfer-ownership": { - "put": { - "operationId": "schedulesTransferOwnership", - "summary": "Transfer schedule ownership", - "tags": [ - "Schedules" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The UUID of the scheduled task. Can be found in the schedule's URL after /schedules/.", - "name": "scheduleId", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SchedulesTransferOwnershipBody" - } - } - } - }, - "responses": { - "200": { - "description": "Ownership transferred successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid user ID" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - must be schedule owner or have manage permission" - }, - "404": { - "description": "Schedule or user not found" - } - } - } - }, - "/api/scim/v2/Users": { - "get": { - "operationId": "scimUsersList", - "summary": "List SCIM users", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "pattern": "^-?\\d*\\.?\\d+$", - "default": 100, - "description": "Maximum number of results to return", - "example": 100 - }, - "required": false, - "description": "Maximum number of results to return", - "name": "count", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "SCIM filter expression", - "example": "userName eq \"user@example.com\"" - }, - "required": false, - "description": "SCIM filter expression", - "name": "filter", - "in": "query" - }, - { - "schema": { - "type": "string", - "pattern": "^-?\\d*\\.?\\d+$", - "default": 1, - "description": "Index of the first result to return (1-based)", - "example": 1 - }, - "required": false, - "description": "Index of the first result to return (1-based)", - "name": "startIndex", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of SCIM users", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimUsersListResponse" - } - } - } - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - } - } - }, - "post": { - "operationId": "scimUsersCreate", - "summary": "Create SCIM user", - "tags": [ - "SCIM" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimUserCreateRequest" - } - } - } - }, - "responses": { - "201": { - "description": "SCIM user created", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimUserResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - }, - "409": { - "description": "User with this email already exists" - } - } - } - }, - "/api/scim/v2/Users/{id}": { - "get": { - "operationId": "scimUsersGet", - "summary": "Get SCIM user", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "SCIM user ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "SCIM user ID", - "name": "id", - "in": "path" - } - ], - "responses": { - "200": { - "description": "SCIM user details", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimUserResponse" - } - } - } - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - }, - "404": { - "description": "User not found" - } - } - }, - "put": { - "operationId": "scimUsersReplace", - "summary": "Replace SCIM user", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "SCIM user ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "SCIM user ID", - "name": "id", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimUserPutRequest" - } - } - } - }, - "responses": { - "200": { - "description": "SCIM user replaced", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimUserResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - }, - "404": { - "description": "User not found" - } - } - }, - "patch": { - "operationId": "scimUsersUpdate", - "summary": "Update SCIM user", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "SCIM user ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "SCIM user ID", - "name": "id", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimUserPatchRequest" - } - } - } - }, - "responses": { - "200": { - "description": "SCIM user updated", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimUserResponse" - } - } - } - }, - "400": { - "description": "Invalid patch operations" - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - }, - "404": { - "description": "User not found" - } - } - }, - "delete": { - "operationId": "scimUsersDelete", - "summary": "Delete SCIM user", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "SCIM user ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "SCIM user ID", - "name": "id", - "in": "path" - } - ], - "responses": { - "204": { - "description": "SCIM user deleted" - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - }, - "404": { - "description": "User not found" - } - } - } - }, - "/api/scim/v2/embed/Users": { - "get": { - "description": "List embed users. Embed users are externally-managed users created via the embed SSO flow.", - "operationId": "scimEmbedUsersList", - "summary": "List embed users", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "pattern": "^-?\\d*\\.?\\d+$", - "default": 100, - "description": "Maximum number of results to return", - "example": 100 - }, - "required": false, - "description": "Maximum number of results to return", - "name": "count", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "SCIM filter expression", - "example": "userName eq \"user@example.com\"" - }, - "required": false, - "description": "SCIM filter expression", - "name": "filter", - "in": "query" - }, - { - "schema": { - "type": "string", - "pattern": "^-?\\d*\\.?\\d+$", - "default": 1, - "description": "Index of the first result to return (1-based)", - "example": 1 - }, - "required": false, - "description": "Index of the first result to return (1-based)", - "name": "startIndex", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of embed users", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimUsersListResponse" - } - } - } - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - } - } - } - }, - "/api/scim/v2/embed/Users/{id}": { - "get": { - "description": "Get details for a specific embed user.", - "operationId": "scimEmbedUsersGet", - "summary": "Get embed user", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "SCIM user ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "SCIM user ID", - "name": "id", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Embed user details", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimUserResponse" - } - } - } - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - }, - "404": { - "description": "Embed user not found" - } - } - }, - "delete": { - "description": "Permanently delete an embed user. Unlike standard SCIM user deletion which soft-deletes, this performs a hard delete.", - "operationId": "scimEmbedUsersDelete", - "summary": "Delete embed user", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "SCIM user ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "SCIM user ID", - "name": "id", - "in": "path" - } - ], - "responses": { - "204": { - "description": "Embed user permanently deleted" - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - }, - "404": { - "description": "Embed user not found" - } - } - } - }, - "/api/scim/v2/Groups": { - "get": { - "operationId": "scimGroupsList", - "summary": "List SCIM groups", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "pattern": "^-?\\d*\\.?\\d+$", - "default": 100, - "description": "Maximum number of results to return", - "example": 100 - }, - "required": false, - "description": "Maximum number of results to return", - "name": "count", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "members" - ], - "description": "Attributes to exclude from the response", - "example": "members" - }, - "required": false, - "description": "Attributes to exclude from the response", - "name": "excludedAttributes", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "SCIM filter expression", - "example": "displayName eq \"Engineering\"" - }, - "required": false, - "description": "SCIM filter expression", - "name": "filter", - "in": "query" - }, - { - "schema": { - "type": "string", - "pattern": "^-?\\d*\\.?\\d+$", - "default": 1, - "description": "Index of the first result to return (1-based)", - "example": 1 - }, - "required": false, - "description": "Index of the first result to return (1-based)", - "name": "startIndex", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of SCIM groups", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimGroupsListResponse" - } - } - } - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - } - } - }, - "post": { - "operationId": "scimGroupsCreate", - "summary": "Create SCIM group", - "tags": [ - "SCIM" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimGroupsCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "SCIM group created", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimGroupResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - }, - "409": { - "description": "Group with this name already exists" - } - } - } - }, - "/api/scim/v2/Groups/{miniUuid}": { - "get": { - "operationId": "scimGroupsGet", - "summary": "Get SCIM group", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "required": true, - "description": "Short identifier of the group", - "name": "miniUuid", - "in": "path" - }, - { - "schema": { - "type": "string", - "enum": [ - "members" - ], - "description": "Attributes to exclude from the response", - "example": "members" - }, - "required": false, - "description": "Attributes to exclude from the response", - "name": "excludedAttributes", - "in": "query" - } - ], - "responses": { - "200": { - "description": "SCIM group details", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimGroupResponse" - } - } - } - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - }, - "404": { - "description": "Group not found" - } - } - }, - "put": { - "operationId": "scimGroupsReplace", - "summary": "Replace SCIM group", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "required": true, - "description": "Short identifier of the group", - "name": "miniUuid", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimGroupsReplaceBody" - } - } - } - }, - "responses": { - "200": { - "description": "SCIM group replaced", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimGroupResponse" - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - }, - "404": { - "description": "Group not found" - } - } - }, - "patch": { - "operationId": "scimGroupsUpdate", - "summary": "Update SCIM group", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "required": true, - "description": "Short identifier of the group", - "name": "miniUuid", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimGroupsPatchBody" - } - } - } - }, - "responses": { - "200": { - "description": "SCIM group updated", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ScimGroupResponse" - } - } - } - }, - "400": { - "description": "Invalid patch operations" - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - }, - "404": { - "description": "Group not found" - } - } - }, - "delete": { - "operationId": "scimGroupsDelete", - "summary": "Delete SCIM group", - "tags": [ - "SCIM" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "required": true, - "description": "Short identifier of the group", - "name": "miniUuid", - "in": "path" - } - ], - "responses": { - "204": { - "description": "SCIM group deleted" - }, - "401": { - "description": "Authentication required (SCIM bearer token)" - }, - "404": { - "description": "Group not found" - } - } - } - }, - "/api/unstable/documents/{identifier}/export": { - "get": { - "operationId": "unstableDocumentsExport", - "summary": "Export document (unstable)", - "tags": [ - "Unstable" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (miniUuid or full UUID)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (miniUuid or full UUID)", - "name": "identifier", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Document export data", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentExportResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/unstable/documents/import": { - "post": { - "operationId": "unstableDocumentsImport", - "summary": "Import document (unstable)", - "tags": [ - "Unstable" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentImportBody" - } - } - } - }, - "responses": { - "201": { - "description": "Document imported successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentImportResponse" - } - } - } - }, - "400": { - "description": "Invalid export data" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Base model not found" - } - } - } - }, - "/api/v1/user-attributes": { - "get": { - "description": "Returns all user attribute definitions in the organization, including system-defined attributes (e.g. omni_user_id, omni_user_email) and custom attributes.", - "operationId": "userAttributesList", - "summary": "List all user attribute definitions", - "tags": [ - "User Attributes" - ], - "responses": { - "200": { - "description": "List of all user attribute definitions in the organization", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserAttributesListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Insufficient permissions" - } - } - } - }, - "/api/v1/uploads": { - "get": { - "operationId": "uploadsList", - "summary": "List uploads", - "tags": [ - "Uploads" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction (default: desc)", - "example": "desc" - }, - "required": false, - "description": "Sort direction (default: desc)", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "createdAt", - "fileName", - "updatedAt" - ], - "default": "updatedAt", - "description": "Field to sort by (default: updatedAt)" - }, - "required": false, - "description": "Field to sort by (default: updatedAt)", - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by connection ID" - }, - "required": false, - "description": "Filter by connection ID", - "name": "connectionId", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by model ID. Shared models return connection uploads; workbook models return their own uploads." - }, - "required": false, - "description": "Filter by model ID. Shared models return connection uploads; workbook models return their own uploads.", - "name": "modelId", - "in": "query" - }, - { - "schema": { - "type": "string", - "maxLength": 256, - "description": "Search term to filter by file name" - }, - "required": false, - "description": "Search term to filter by file name", - "name": "searchTerm", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "csv", - "spreadsheet" - ], - "default": "csv", - "description": "Filter by upload type (default: csv)" - }, - "required": false, - "description": "Filter by upload type (default: csv)", - "name": "type", - "in": "query" - } - ], - "responses": { - "200": { - "description": "List of uploads with metadata", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UploadsListResponse" - } - } - } - }, - "400": { - "description": "Invalid query parameters" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model not found (when modelId is provided)" - } - } - }, - "post": { - "operationId": "uploadsCreate", - "summary": "Upload CSV file", - "tags": [ - "Uploads" - ], - "requestBody": { - "required": true, - "content": { - "multipart/form-data": { - "schema": { - "$ref": "#/components/schemas/UploadCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "CSV uploaded successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UploadCreateResponse" - } - } - } - }, - "400": { - "description": "Invalid request (missing fields, invalid file type, or CSV parsing failed)" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Model or branch not found" - } - } - } - }, - "/api/v1/uploads/{uploadId}": { - "delete": { - "operationId": "uploadsDelete", - "summary": "Delete an upload", - "tags": [ - "Uploads" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "ID of the upload to delete" - }, - "required": true, - "description": "ID of the upload to delete", - "name": "uploadId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Upload deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UploadDeleteResponse" - } - } - } - }, - "400": { - "description": "Invalid upload ID format" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Upload not found or already deleted" - } - } - } - }, - "/api/v1/users/{id}/model-roles": { - "get": { - "operationId": "usersGetModelRoles", - "summary": "Get user model roles", - "tags": [ - "Users" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "User membership ID", - "name": "id", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter results to a specific connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": false, - "description": "Filter results to a specific connection", - "name": "connectionId", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter results to a specific model", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": false, - "description": "Filter results to a specific model", - "name": "modelId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "User model role assignments", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UsersGetModelRolesResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - }, - "404": { - "description": "User not found" - } - } - }, - "post": { - "operationId": "usersAssignModelRole", - "summary": "Assign model role to user", - "tags": [ - "Users" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "User membership ID", - "name": "id", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UsersAssignModelRoleBody" - } - } - } - }, - "responses": { - "200": { - "description": "Role assigned successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UsersAssignModelRoleResponse" - } - } - } - }, - "400": { - "description": "Invalid request - connectionId or modelId required" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - }, - "404": { - "description": "User, model, or connection not found" - } - } - } - }, - "/api/v1/users/email-only": { - "get": { - "operationId": "usersListEmailOnly", - "summary": "List email-only users", - "tags": [ - "Users" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Cursor for pagination" - }, - "required": false, - "description": "Cursor for pagination", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by email address", - "example": "user@example.com" - }, - "required": false, - "description": "Filter by email address", - "name": "email", - "in": "query" - }, - { - "schema": { - "type": "number", - "minimum": 1, - "maximum": 20, - "default": 20, - "description": "Number of results per page (max 20)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (max 20)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Paginated list of email-only users", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UsersListEmailOnlyResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - } - } - }, - "post": { - "operationId": "usersCreateEmailOnly", - "summary": "Create or update email-only user", - "tags": [ - "Users" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UsersCreateEmailOnlyBody" - } - } - } - }, - "responses": { - "200": { - "description": "Email-only user created or updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UsersCreateEmailOnlyResponse" - } - } - } - }, - "400": { - "description": "Invalid email address or failed to create user" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - } - } - } - }, - "/api/v1/users/email-only/bulk": { - "post": { - "operationId": "usersCreateEmailOnlyBulk", - "summary": "Create email-only users in bulk", - "tags": [ - "Users" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UsersCreateEmailOnlyBulkBody" - } - } - } - }, - "responses": { - "201": { - "description": "Email-only users created successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UsersCreateEmailOnlyBulkResponse" - } - } - } - }, - "400": { - "description": "Invalid request - must provide 1-20 users with valid emails" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - } - } - } - }, - "/api/v1/user-groups/{id}/model-roles": { - "get": { - "operationId": "userGroupsGetModelRoles", - "summary": "Get user group model roles", - "tags": [ - "Users" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "User group short identifier (miniUuid)", - "example": "abc123" - }, - "required": true, - "description": "User group short identifier (miniUuid)", - "name": "id", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter results to a specific connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": false, - "description": "Filter results to a specific connection", - "name": "connectionId", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter results to a specific model", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": false, - "description": "Filter results to a specific model", - "name": "modelId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "User group model role assignments", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserGroupsGetModelRolesResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - }, - "404": { - "description": "User group not found" - } - } - }, - "post": { - "operationId": "userGroupsAssignModelRole", - "summary": "Assign model role to user group", - "tags": [ - "Users" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "User group short identifier (miniUuid)", - "example": "abc123" - }, - "required": true, - "description": "User group short identifier (miniUuid)", - "name": "id", - "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserGroupsAssignModelRoleBody" - } - } - } - }, - "responses": { - "200": { - "description": "Role assigned successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserGroupsAssignModelRoleResponse" - } - } - } - }, - "400": { - "description": "Invalid request - connectionId or modelId required" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - }, - "404": { - "description": "User group, model, or connection not found" - } - } - } - }, - "/api/v1/whoami": { - "get": { - "description": "Returns the authenticated caller's own identity, API key scope, organization role, and resolved per-model permissions. Self-scoped and available to non-admins: it lets a caller decide whether an action is permitted without attempting it. Pass `modelId` to scope `rolesByModel` to specific models.", - "operationId": "whoami", - "summary": "Get current identity and permissions (whoami)", - "tags": [ - "Whoami" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Optional model filter. A single model id or a comma-separated list. When provided, `rolesByModel` contains only these models. When omitted, models the caller can access are returned (up to a limit; see `rolesByModelTruncated`).", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": false, - "description": "Optional model filter. A single model id or a comma-separated list. When provided, `rolesByModel` contains only these models. When omitted, models the caller can access are returned (up to a limit; see `rolesByModelTruncated`).", - "name": "modelId", - "in": "query" - } - ], - "responses": { - "200": { - "description": "Caller's identity, key scope, org role, and per-model permissions", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/WhoamiResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "404": { - "description": "One or more requested `modelId`s do not exist or are not accessible to the caller" - } - } - } - } - }, - "webhooks": {} -} \ No newline at end of file diff --git a/spec/provenance.json b/spec/provenance.json new file mode 100644 index 0000000..79313e2 --- /dev/null +++ b/spec/provenance.json @@ -0,0 +1,5 @@ +{ + "source": "omni repo @ 7805fc5e5dcc6bcd3fbc39885b5f675fa8470195", + "spec_sha256": "8777d18dde709fbf3c1691141774fbc8cc1baba24d8a1ccd8487717322547c48", + "synced_at": "2026-07-16T19:52:43Z" +} \ No newline at end of file From 9034ce6aa215ca1657addeb0b2329925ae8aed55 Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Thu, 16 Jul 2026 12:56:27 -0700 Subject: [PATCH 07/11] Document versioning strategy and seed changelog VERSIONING.md covers the semver contract (independent of the API's info.version), how to classify a spec sync as major/minor/patch including oasdiff breaking-change detection, the generator-upgrade policy, and the release process through the existing PyPI trusted publishing workflow. CHANGELOG.md seeds the 1.0.0 entry. Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 20 ++++++++++++++++ README.md | 8 +------ VERSIONING.md | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 VERSIONING.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..25eec3e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +## 1.0.0 (unreleased) + +Full rewrite: the SDK is now generated from the official Omni OpenAPI spec. + +- **Breaking:** the hand-written `OmniAPI` class is removed. Queries move to + `omni_python_sdk.helpers` (`client_from_env`, `run_query_blocking`, + `wait_query_blocking`); all other operations are generated endpoint modules + under `omni_python_sdk.api.` — see the README migration table. +- **Breaking:** errors now raise (`httpx` exceptions / typed responses) + instead of printing and returning `None`. +- **Breaking:** Python 3.10+ required (was 3.9+). +- Coverage grows from ~30 hand-written endpoints to all 195 operations in the + spec (queries, documents, models, connections, SCIM, schedules, AI, embed, + and more), with typed models and sync + async variants. +- Packaging modernized to `pyproject.toml`; fixes the incorrect `dotenv` + dependency (now `python-dotenv`). +- Spec synced from omni repo commit `7805fc5e5dcc6bcd3fbc39885b5f675fa8470195` + (see `spec/provenance.json`). diff --git a/README.md b/README.md index 2facac7..3c5b890 100644 --- a/README.md +++ b/README.md @@ -118,13 +118,7 @@ Everything in `omni_python_sdk/` **except `helpers.py`** is generated — don't **Reviewing a spec-sync PR:** review the `spec/openapi.json` diff and any hand-written changes; skip the generated diff. That's safe because CI's drift check proves the generated code is a pure function of the checked-in spec. -**Versioning:** the SDK follows its own semver, independent of the API's `info.version`: - -- **Major** — breaking changes to the generated surface (removed/renamed endpoints, fields, or types) or to `helpers.py` -- **Minor** — new endpoints, models, or optional fields (most spec syncs) -- **Patch** — regeneration fixes, docs, dependency bumps - -Generator upgrades (the `openapi-python-client` pin in `pyproject.toml`) can rewrite every generated file with no API change — land those as their own clearly-labeled PR, never mixed with a spec sync. +**Versioning:** the SDK follows its own semver, independent of the API's `info.version` — major for breaking surface changes, minor for new endpoints/fields (most spec syncs), patch for regeneration fixes. See [VERSIONING.md](VERSIONING.md) for how to classify a spec sync (including mechanical breaking-change detection with oasdiff), how to handle generator upgrades, and the release process. Changes are tracked in [CHANGELOG.md](CHANGELOG.md). ## Development diff --git a/VERSIONING.md b/VERSIONING.md new file mode 100644 index 0000000..bb64d3e --- /dev/null +++ b/VERSIONING.md @@ -0,0 +1,64 @@ +# Versioning + +This SDK follows [semantic versioning](https://semver.org/). The SDK version is +**independent of the API's `info.version`** in the OpenAPI spec and of Omni app +releases — it describes the SDK's own surface: the generated client, the +hand-written `helpers.py`, and the package's runtime requirements. + +The version lives in one place: `pyproject.toml`. + +## What each bump means + +| Bump | When | Examples | +|---|---|---| +| **Major** | A change a working program could break on | Endpoint or model removed/renamed; parameter or field type changed; required parameter added; `helpers.py` signature changed; Python version floor raised; generator upgrade that reshapes generated signatures | +| **Minor** | Purely additive surface | New endpoints or tags; new models; new optional fields or parameters; new helper functions | +| **Patch** | No surface change | Regeneration fixes; docs; dependency pin adjustments; internal generation-pipeline changes | + +Most spec syncs are **minor**. The Omni API's own CI runs breaking-change +detection (oasdiff) before spec changes merge, so removals should be rare — +but the SDK sync is where they become a package consumer's problem, so +classify each sync explicitly. + +## Classifying a spec sync + +1. Sync the spec: `scripts/generate.sh --source ../omni/.../openapi.json` +2. Look at the diff summary: `git diff --stat spec/openapi.json` and the + generated diff (`git diff --stat omni_python_sdk/`). Deleted or renamed + modules under `omni_python_sdk/api/` or `omni_python_sdk/models/` are a + strong breaking signal; only-added files suggest minor. +3. For a mechanical verdict, run [oasdiff](https://github.com/oasdiff/oasdiff) + against the previous spec: + + ```bash + git show HEAD:spec/openapi.json > /tmp/openapi.old.json + oasdiff breaking /tmp/openapi.old.json spec/openapi.json + ``` + + Any reported breaking change → major bump (or push back on the API change + upstream before shipping it). + +## Generator upgrades + +The `openapi-python-client` version is pinned in `pyproject.toml` (dev extras). +Upgrading it can rewrite every generated file with **no API change** — and can +also change generated method signatures, which is breaking for SDK users even +though the API didn't move. + +- Land generator upgrades as their own PR, clearly labeled, never mixed with a + spec sync. +- Diff the generated output before/after: if signatures or model shapes + changed, it's a major bump; if only formatting/internals changed, patch. + +## Release process + +1. Decide the bump (above) and update `version` in `pyproject.toml`. +2. Add a `CHANGELOG.md` entry: what changed in API surface terms (endpoints + added/removed, helpers changed), and the omni commit from + `spec/provenance.json` the spec was synced from. +3. Merge to `main`, then create a GitHub release tagged `vX.Y.Z`. +4. The `python-publish.yml` workflow builds and publishes to PyPI via trusted + publishing on release publish — no manual upload. + +Every release is traceable: the git tag pins the spec (`spec/openapi.json`) +and `spec/provenance.json` pins the omni repo commit that spec came from. From e0e79bea45b4b90ed60b89b8ab90dbfc8bb55101 Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Thu, 16 Jul 2026 13:33:28 -0700 Subject: [PATCH 08/11] Gate generator dep on Python 3.11+ to fix 3.10 CI install openapi-python-client 0.29 requires Python >=3.11, which broke 'pip install -e .[dev]' on 3.10. The generator is codegen-only tooling; the SDK itself still supports 3.10. Co-Authored-By: Claude Fable 5 --- README.md | 2 +- pyproject.toml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3c5b890..6b46779 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ Version 1.0 is a full rewrite: the hand-written `OmniAPI` class is gone, replace ## Regenerating the SDK -The client is generated from the vendored spec in `spec/openapi.json` using [openapi-python-client](https://github.com/openapi-generators/openapi-python-client): +The client is generated from the vendored spec in `spec/openapi.json` using [openapi-python-client](https://github.com/openapi-generators/openapi-python-client) (the generator needs Python 3.11+, though the SDK itself runs on 3.10): ```bash pip install openapi-python-client diff --git a/pyproject.toml b/pyproject.toml index 0ac8da2..9648161 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,8 @@ Documentation = "https://docs.omni.co/docs/API/" [project.optional-dependencies] dev = [ "pytest>=8.0.0", - "openapi-python-client>=0.29.0,<0.30.0", + # Codegen tool only; requires Python 3.11+ (the SDK itself supports 3.10) + "openapi-python-client>=0.29.0,<0.30.0; python_version >= '3.11'", "ruff", "pandas", ] From aa6d129b74563db90f94984ce89342e1108f14ea Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Thu, 16 Jul 2026 13:44:14 -0700 Subject: [PATCH 09/11] Surface query job errors in run_query_blocking A FAILED job (e.g. a bad view name) previously raised the generic 'No result found in the response'; now the error type and message from the job status line are included. Found during live smoke testing. Co-Authored-By: Claude Fable 5 --- omni_python_sdk/helpers.py | 5 +++++ tests/test_helpers.py | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/omni_python_sdk/helpers.py b/omni_python_sdk/helpers.py index 1a20556..205545d 100644 --- a/omni_python_sdk/helpers.py +++ b/omni_python_sdk/helpers.py @@ -68,6 +68,11 @@ def run_query_blocking( data_payload = next((line for line in lines if "result" in line), None) if data_payload is None: + failed = next((line for line in lines if line.get("status") == "FAILED"), None) + if failed is not None: + raise ValueError( + f"Query failed ({failed.get('error_type', 'unknown')}): {failed.get('error_message', 'no message')}" + ) raise ValueError("No result found in the query response.") raw_arrow_data = base64.b64decode(data_payload["result"]) diff --git a/tests/test_helpers.py b/tests/test_helpers.py index fdffbd9..1f8ccb1 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -75,6 +75,25 @@ def handler(request: httpx.Request) -> httpx.Response: assert table.equals(TABLE) +def test_run_query_blocking_failed_job_raises_with_message(): + def handler(request: httpx.Request) -> httpx.Response: + return _ndjson_response( + [ + {"jobs_submitted": {}}, + { + "job_id": "job-1", + "status": "FAILED", + "error_type": "PLAN", + "error_message": 'No such view "order_items"', + }, + {"timed_out": "false", "remaining_job_ids": []}, + ] + ) + + with pytest.raises(ValueError, match=r'Query failed \(PLAN\): No such view "order_items"'): + run_query_blocking(_client_with_transport(handler), {"query": {}}) + + def test_run_query_blocking_no_result_raises(): def handler(request: httpx.Request) -> httpx.Response: return _ndjson_response([{"timed_out": "false"}]) From 613aee8b7692ce2dd25c8412312669f877265566 Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Thu, 16 Jul 2026 13:48:38 -0700 Subject: [PATCH 10/11] Warn against calling generated query modules directly Co-Authored-By: Claude Fable 5 --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 6b46779..bd047b3 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,13 @@ df = table.to_pandas() Tip: copy a ready-made query body from any workbook via **View → Query Structure**. +> **Note:** always use these helpers for queries — don't call the generated +> `omni_python_sdk.api.query.query_run` / `query_wait` modules directly. The +> spec declares these responses as JSON, but the endpoints actually stream +> NDJSON with base64-encoded Arrow IPC data, which the generated response +> parsing can't handle. The helpers own that decoding (and job polling, and +> surfacing query errors). + ## Calling any endpoint Every API operation is a module under `omni_python_sdk.api.`, with four variants: `sync`, `sync_detailed`, `asyncio`, and `asyncio_detailed`. From 5e2bec12d24a12f7fb8841b582cb6c55a78454fc Mon Sep 17 00:00:00 2001 From: Jamie Davidson Date: Wed, 22 Jul 2026 12:00:28 -0700 Subject: [PATCH 11/11] Sync spec: NDJSON query responses modeled upstream; new endpoints Spec synced from omni repo main @ c3fe793 (fixes exploreomni/omni#57144): - query/run and query/wait now declare their real content types (text/ndjson et al) with typed stream-line models (QueryStreamJobLine, QueryStreamFooterLine, ...); the JSON-only QueryRun/WaitResponse models are gone. The generated modules still can't consume a multi-line stream at runtime, so helpers.run_query_blocking remains the query path (README note updated). - New endpoints: AI credit-control entity groups, AI model suggestions, documents_v2_remove_dashboard (128 paths / 201 operations total) - Assorted model updates (documents v2, eval runs, git settings) Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 7 +- README.md | 9 +- .../ai_credit_controls_entity_groups_list.py | 225 +++ ...ai_credit_controls_entity_groups_update.py | 216 +++ .../api/ai/ai_credit_controls_get.py | 24 +- .../api/ai/ai_credit_controls_update.py | 52 +- omni_python_sdk/api/ai/ai_generate_query.py | 16 +- omni_python_sdk/api/ai/ai_job_submit.py | 12 +- .../api/ai_eval/ai_eval_runs_create.py | 24 +- .../model_suggestions_generate.py | 210 +++ .../model_suggestions_run_get.py | 198 +++ .../model_suggestions_run_latest.py | 188 +++ .../api/ai_routines/routine_trigger.py | 24 +- .../documents/documents_get_permissions.py | 48 +- .../api/documents/documents_v2_get_draft.py | 16 +- .../documents_v2_patch_draft_by_identifier.py | 16 +- .../documents_v2_remove_dashboard.py | 245 +++ omni_python_sdk/api/models/models_create.py | 16 +- .../api/models/models_git_create.py | 12 + .../api/models/models_git_update.py | 20 + omni_python_sdk/api/query/query_run.py | 65 +- omni_python_sdk/api/query/query_wait.py | 65 +- omni_python_sdk/models/__init__.py | 62 +- .../models/agentic_job_attachment.py | 81 + ...it_controls_entity_groups_list_response.py | 90 ++ ...ntity_groups_list_response_records_item.py | 77 + .../models/ai_credit_controls_response.py | 15 + .../models/ai_credit_controls_update_body.py | 22 + .../ai_entity_group_credit_limit_entry.py | 76 + .../ai_entity_group_credit_limits_response.py | 79 + ...edit_limits_response_entity_groups_item.py | 84 + ..._entity_group_credit_limits_update_body.py | 57 + omni_python_sdk/models/ai_job_submit_body.py | 29 +- .../models/create_model_schema_base.py | 24 +- ...ate_model_schema_base_model_kind_type_4.py | 15 + omni_python_sdk/models/document_abilities.py | 150 ++ .../documents_get_permissions_response.py | 23 +- ...cuments_update_permission_settings_body.py | 36 + .../models/documents_v2_create_draft_body.py | 18 + .../models/documents_v2_patch_draft_body.py | 18 + .../models/documents_v2_read_response.py | 9 + omni_python_sdk/models/eval_run_detail.py | 13 +- omni_python_sdk/models/eval_run_list_item.py | 8 + omni_python_sdk/models/eval_run_result.py | 42 + omni_python_sdk/models/eval_run_stats.py | 2 +- .../models/eval_runs_cancel_response.py | 2 +- .../eval_runs_create_body_run_config.py | 10 + .../models/eval_runs_create_response.py | 6 +- .../models/generate_suggestions_response.py | 75 + .../generate_suggestions_response_status.py | 13 + .../models/models_git_create_body.py | 22 + .../models/models_git_create_response.py | 3 +- .../models_git_create_response_auth_method.py | 3 +- .../models/models_git_get_response.py | 3 +- .../models_git_get_response_auth_method.py | 3 +- .../models/models_git_update_body.py | 22 + .../models/models_git_update_response.py | 3 +- .../models_git_update_response_auth_method.py | 3 +- omni_python_sdk/models/query_run_response.py | 84 - ...onse.py => query_run_response_200_item.py} | 28 +- .../models/query_stream_footer_line.py | 77 + .../query_stream_footer_line_timed_out.py | 14 + .../models/query_stream_job_line.py | 245 +++ ...ery_stream_job_line_column_name_mapping.py | 47 + .../query_stream_job_line_stream_stats.py | 47 + .../models/query_stream_job_line_used_keys.py | 47 + .../query_stream_jobs_submitted_line.py | 69 + ...ream_jobs_submitted_line_jobs_submitted.py | 75 + omni_python_sdk/models/suggestion_run.py | 204 +++ .../models/suggestion_run_error_type_0.py | 47 + .../models/suggestion_run_latest_response.py | 67 + .../suggestion_run_latest_response_run.py | 204 +++ .../models/suggestion_run_status.py | 16 + .../models/suggestion_run_trigger_source.py | 14 + .../suggestion_run_triggered_by_type_0.py | 78 + .../models/suggestions_cooldown_response.py | 86 + spec/openapi.json | 1378 +++++++++++++++-- spec/provenance.json | 6 +- 78 files changed, 5336 insertions(+), 403 deletions(-) create mode 100644 omni_python_sdk/api/ai/ai_credit_controls_entity_groups_list.py create mode 100644 omni_python_sdk/api/ai/ai_credit_controls_entity_groups_update.py create mode 100644 omni_python_sdk/api/ai_model_suggestions/model_suggestions_generate.py create mode 100644 omni_python_sdk/api/ai_model_suggestions/model_suggestions_run_get.py create mode 100644 omni_python_sdk/api/ai_model_suggestions/model_suggestions_run_latest.py create mode 100644 omni_python_sdk/api/documents/documents_v2_remove_dashboard.py create mode 100644 omni_python_sdk/models/agentic_job_attachment.py create mode 100644 omni_python_sdk/models/ai_credit_controls_entity_groups_list_response.py create mode 100644 omni_python_sdk/models/ai_credit_controls_entity_groups_list_response_records_item.py create mode 100644 omni_python_sdk/models/ai_entity_group_credit_limit_entry.py create mode 100644 omni_python_sdk/models/ai_entity_group_credit_limits_response.py create mode 100644 omni_python_sdk/models/ai_entity_group_credit_limits_response_entity_groups_item.py create mode 100644 omni_python_sdk/models/ai_entity_group_credit_limits_update_body.py create mode 100644 omni_python_sdk/models/create_model_schema_base_model_kind_type_4.py create mode 100644 omni_python_sdk/models/document_abilities.py create mode 100644 omni_python_sdk/models/generate_suggestions_response.py create mode 100644 omni_python_sdk/models/generate_suggestions_response_status.py delete mode 100644 omni_python_sdk/models/query_run_response.py rename omni_python_sdk/models/{query_wait_response.py => query_run_response_200_item.py} (62%) create mode 100644 omni_python_sdk/models/query_stream_footer_line.py create mode 100644 omni_python_sdk/models/query_stream_footer_line_timed_out.py create mode 100644 omni_python_sdk/models/query_stream_job_line.py create mode 100644 omni_python_sdk/models/query_stream_job_line_column_name_mapping.py create mode 100644 omni_python_sdk/models/query_stream_job_line_stream_stats.py create mode 100644 omni_python_sdk/models/query_stream_job_line_used_keys.py create mode 100644 omni_python_sdk/models/query_stream_jobs_submitted_line.py create mode 100644 omni_python_sdk/models/query_stream_jobs_submitted_line_jobs_submitted.py create mode 100644 omni_python_sdk/models/suggestion_run.py create mode 100644 omni_python_sdk/models/suggestion_run_error_type_0.py create mode 100644 omni_python_sdk/models/suggestion_run_latest_response.py create mode 100644 omni_python_sdk/models/suggestion_run_latest_response_run.py create mode 100644 omni_python_sdk/models/suggestion_run_status.py create mode 100644 omni_python_sdk/models/suggestion_run_trigger_source.py create mode 100644 omni_python_sdk/models/suggestion_run_triggered_by_type_0.py create mode 100644 omni_python_sdk/models/suggestions_cooldown_response.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 25eec3e..5d2f7b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,5 +16,8 @@ Full rewrite: the SDK is now generated from the official Omni OpenAPI spec. and more), with typed models and sync + async variants. - Packaging modernized to `pyproject.toml`; fixes the incorrect `dotenv` dependency (now `python-dotenv`). -- Spec synced from omni repo commit `7805fc5e5dcc6bcd3fbc39885b5f675fa8470195` - (see `spec/provenance.json`). +- Spec synced from omni repo commit `c3fe7934808a8086999643252e5c19d0917ed171` + (see `spec/provenance.json`), which fixes the query endpoints' declared + content types to NDJSON with typed stream-line models + (exploreomni/omni#57144) and adds AI credit-control entity groups, model + suggestions, and dashboard-removal endpoints (128 paths / 201 operations). diff --git a/README.md b/README.md index bd047b3..d05444f 100644 --- a/README.md +++ b/README.md @@ -62,10 +62,11 @@ Tip: copy a ready-made query body from any workbook via **View → Query Structu > **Note:** always use these helpers for queries — don't call the generated > `omni_python_sdk.api.query.query_run` / `query_wait` modules directly. The -> spec declares these responses as JSON, but the endpoints actually stream -> NDJSON with base64-encoded Arrow IPC data, which the generated response -> parsing can't handle. The helpers own that decoding (and job polling, and -> surfacing query errors). +> endpoints stream NDJSON (multiple lines per response) with base64-encoded +> Arrow IPC data; the spec now models the line schemas (`QueryStreamJobLine` +> etc.), but the generated response parsing can't consume a multi-line stream +> at runtime. The helpers own that decoding (and job polling, and surfacing +> query errors). ## Calling any endpoint diff --git a/omni_python_sdk/api/ai/ai_credit_controls_entity_groups_list.py b/omni_python_sdk/api/ai/ai_credit_controls_entity_groups_list.py new file mode 100644 index 0000000..f138791 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_credit_controls_entity_groups_list.py @@ -0,0 +1,225 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_credit_controls_entity_groups_list_response import AiCreditControlsEntityGroupsListResponse +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...types import UNSET, Response, Unset + + +def _get_kwargs( + *, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, +) -> dict[str, Any]: + + params: dict[str, Any] = {} + + params["cursor"] = cursor + + params["pageSize"] = page_size + + params = {k: v for k, v in params.items() if v is not UNSET and v is not None} + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/ai/credit-controls/entity-groups", + "params": params, + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiCreditControlsEntityGroupsListResponse | ApiError400 | ApiError401 | ApiError403 | None: + if response.status_code == 200: + response_200 = AiCreditControlsEntityGroupsListResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiCreditControlsEntityGroupsListResponse | ApiError400 | ApiError401 | ApiError403]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, +) -> Response[AiCreditControlsEntityGroupsListResponse | ApiError400 | ApiError401 | ApiError403]: + """List individual entity groups' AI credit limits + + List the organization's active individual embed entity-group AI credit limits, keyed by the embed + `entity` string. Only entity groups with an individual limit appear — everyone else follows the org + default. A `null` creditLimit is an explicit unlimited override, distinct from following the + default. Paginated via opaque cursors: pass `pageInfo.nextCursor` from one response as the `cursor` + query parameter on the next request. Requires the same add/remove-users permission as the PATCH. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiCreditControlsEntityGroupsListResponse | ApiError400 | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, +) -> AiCreditControlsEntityGroupsListResponse | ApiError400 | ApiError401 | ApiError403 | None: + """List individual entity groups' AI credit limits + + List the organization's active individual embed entity-group AI credit limits, keyed by the embed + `entity` string. Only entity groups with an individual limit appear — everyone else follows the org + default. A `null` creditLimit is an explicit unlimited override, distinct from following the + default. Paginated via opaque cursors: pass `pageInfo.nextCursor` from one response as the `cursor` + query parameter on the next request. Requires the same add/remove-users permission as the PATCH. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiCreditControlsEntityGroupsListResponse | ApiError400 | ApiError401 | ApiError403 + """ + + return sync_detailed( + client=client, + cursor=cursor, + page_size=page_size, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, +) -> Response[AiCreditControlsEntityGroupsListResponse | ApiError400 | ApiError401 | ApiError403]: + """List individual entity groups' AI credit limits + + List the organization's active individual embed entity-group AI credit limits, keyed by the embed + `entity` string. Only entity groups with an individual limit appear — everyone else follows the org + default. A `null` creditLimit is an explicit unlimited override, distinct from following the + default. Paginated via opaque cursors: pass `pageInfo.nextCursor` from one response as the `cursor` + query parameter on the next request. Requires the same add/remove-users permission as the PATCH. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiCreditControlsEntityGroupsListResponse | ApiError400 | ApiError401 | ApiError403] + """ + + kwargs = _get_kwargs( + cursor=cursor, + page_size=page_size, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + cursor: str | Unset = UNSET, + page_size: int | Unset = 20, +) -> AiCreditControlsEntityGroupsListResponse | ApiError400 | ApiError401 | ApiError403 | None: + """List individual entity groups' AI credit limits + + List the organization's active individual embed entity-group AI credit limits, keyed by the embed + `entity` string. Only entity groups with an individual limit appear — everyone else follows the org + default. A `null` creditLimit is an explicit unlimited override, distinct from following the + default. Paginated via opaque cursors: pass `pageInfo.nextCursor` from one response as the `cursor` + query parameter on the next request. Requires the same add/remove-users permission as the PATCH. + + Args: + cursor (str | Unset): Cursor for pagination (from previous response nextCursor) Example: + eyJpZCI6IjEyMzQ1In0. + page_size (int | Unset): Number of results per page (1-100, integer) Default: 20. Example: + 20. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiCreditControlsEntityGroupsListResponse | ApiError400 | ApiError401 | ApiError403 + """ + + return ( + await asyncio_detailed( + client=client, + cursor=cursor, + page_size=page_size, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_credit_controls_entity_groups_update.py b/omni_python_sdk/api/ai/ai_credit_controls_entity_groups_update.py new file mode 100644 index 0000000..a87afd3 --- /dev/null +++ b/omni_python_sdk/api/ai/ai_credit_controls_entity_groups_update.py @@ -0,0 +1,216 @@ +from http import HTTPStatus +from typing import Any + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.ai_entity_group_credit_limits_response import AiEntityGroupCreditLimitsResponse +from ...models.ai_entity_group_credit_limits_update_body import AiEntityGroupCreditLimitsUpdateBody +from ...models.api_error_400 import ApiError400 +from ...models.api_error_401 import ApiError401 +from ...models.api_error_403 import ApiError403 +from ...models.api_error_404 import ApiError404 +from ...types import Response + + +def _get_kwargs( + *, + body: AiEntityGroupCreditLimitsUpdateBody, +) -> dict[str, Any]: + headers: dict[str, Any] = {} + + _kwargs: dict[str, Any] = { + "method": "patch", + "url": "/api/v1/ai/credit-controls/entity-groups", + } + + _kwargs["json"] = body.to_dict() + + headers["Content-Type"] = "application/json" + + _kwargs["headers"] = headers + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> AiEntityGroupCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + if response.status_code == 200: + response_200 = AiEntityGroupCreditLimitsResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = ApiError400.from_dict(response.json()) + + return response_400 + + if response.status_code == 401: + response_401 = ApiError401.from_dict(response.json()) + + return response_401 + + if response.status_code == 403: + response_403 = ApiError403.from_dict(response.json()) + + return response_403 + + if response.status_code == 404: + response_404 = ApiError404.from_dict(response.json()) + + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[AiEntityGroupCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + *, + client: AuthenticatedClient | Client, + body: AiEntityGroupCreditLimitsUpdateBody, +) -> Response[AiEntityGroupCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + """Set individual entity groups' AI credit limits + + Set individual embed entity groups' AI credit limits in bulk. Each entry names an entity group by + its embed `entity` string and either sets an individual limit (`creditLimit`: a non-negative number, + or `null` for unlimited) or removes one (`useDefaultLimit: true`) so the entity group follows the + org default. Each entity may appear at most once and must have an entity group in the organization. + All updates are applied in one transaction, so either every entry takes effect or none do — an + unknown entity fails the whole request with a 404 naming it. Requires the same add/remove-users + permission as the group settings page and the embed-entity credit-limit feature flag. + + Args: + body (AiEntityGroupCreditLimitsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiEntityGroupCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + *, + client: AuthenticatedClient | Client, + body: AiEntityGroupCreditLimitsUpdateBody, +) -> AiEntityGroupCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + """Set individual entity groups' AI credit limits + + Set individual embed entity groups' AI credit limits in bulk. Each entry names an entity group by + its embed `entity` string and either sets an individual limit (`creditLimit`: a non-negative number, + or `null` for unlimited) or removes one (`useDefaultLimit: true`) so the entity group follows the + org default. Each entity may appear at most once and must have an entity group in the organization. + All updates are applied in one transaction, so either every entry takes effect or none do — an + unknown entity fails the whole request with a 404 naming it. Requires the same add/remove-users + permission as the group settings page and the embed-entity credit-limit feature flag. + + Args: + body (AiEntityGroupCreditLimitsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiEntityGroupCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 + """ + + return sync_detailed( + client=client, + body=body, + ).parsed + + +async def asyncio_detailed( + *, + client: AuthenticatedClient | Client, + body: AiEntityGroupCreditLimitsUpdateBody, +) -> Response[AiEntityGroupCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404]: + """Set individual entity groups' AI credit limits + + Set individual embed entity groups' AI credit limits in bulk. Each entry names an entity group by + its embed `entity` string and either sets an individual limit (`creditLimit`: a non-negative number, + or `null` for unlimited) or removes one (`useDefaultLimit: true`) so the entity group follows the + org default. Each entity may appear at most once and must have an entity group in the organization. + All updates are applied in one transaction, so either every entry takes effect or none do — an + unknown entity fails the whole request with a 404 naming it. Requires the same add/remove-users + permission as the group settings page and the embed-entity credit-limit feature flag. + + Args: + body (AiEntityGroupCreditLimitsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[AiEntityGroupCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404] + """ + + kwargs = _get_kwargs( + body=body, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + *, + client: AuthenticatedClient | Client, + body: AiEntityGroupCreditLimitsUpdateBody, +) -> AiEntityGroupCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 | None: + """Set individual entity groups' AI credit limits + + Set individual embed entity groups' AI credit limits in bulk. Each entry names an entity group by + its embed `entity` string and either sets an individual limit (`creditLimit`: a non-negative number, + or `null` for unlimited) or removes one (`useDefaultLimit: true`) so the entity group follows the + org default. Each entity may appear at most once and must have an entity group in the organization. + All updates are applied in one transaction, so either every entry takes effect or none do — an + unknown entity fails the whole request with a 404 naming it. Requires the same add/remove-users + permission as the group settings page and the embed-entity credit-limit feature flag. + + Args: + body (AiEntityGroupCreditLimitsUpdateBody): + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + AiEntityGroupCreditLimitsResponse | ApiError400 | ApiError401 | ApiError403 | ApiError404 + """ + + return ( + await asyncio_detailed( + client=client, + body=body, + ) + ).parsed diff --git a/omni_python_sdk/api/ai/ai_credit_controls_get.py b/omni_python_sdk/api/ai/ai_credit_controls_get.py index 1ee87d2..8a59278 100644 --- a/omni_python_sdk/api/ai/ai_credit_controls_get.py +++ b/omni_python_sdk/api/ai/ai_credit_controls_get.py @@ -63,9 +63,9 @@ def sync_detailed( """Get AI credit controls Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per- - user credit limit, plus read-only context (the credit limit, usage so far this billing period, and - the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same - AI-admin permission. + user and per-entity-group credit limits, plus read-only context (the credit limit, usage so far this + billing period, and the period bounds). This is the API mirror of the AI Hub credit controls page + and requires the same AI-admin permission. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -91,9 +91,9 @@ def sync( """Get AI credit controls Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per- - user credit limit, plus read-only context (the credit limit, usage so far this billing period, and - the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same - AI-admin permission. + user and per-entity-group credit limits, plus read-only context (the credit limit, usage so far this + billing period, and the period bounds). This is the API mirror of the AI Hub credit controls page + and requires the same AI-admin permission. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -115,9 +115,9 @@ async def asyncio_detailed( """Get AI credit controls Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per- - user credit limit, plus read-only context (the credit limit, usage so far this billing period, and - the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same - AI-admin permission. + user and per-entity-group credit limits, plus read-only context (the credit limit, usage so far this + billing period, and the period bounds). This is the API mirror of the AI Hub credit controls page + and requires the same AI-admin permission. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -141,9 +141,9 @@ async def asyncio( """Get AI credit controls Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per- - user credit limit, plus read-only context (the credit limit, usage so far this billing period, and - the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same - AI-admin permission. + user and per-entity-group credit limits, plus read-only context (the credit limit, usage so far this + billing period, and the period bounds). This is the API mirror of the AI Hub credit controls page + and requires the same AI-admin permission. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. diff --git a/omni_python_sdk/api/ai/ai_credit_controls_update.py b/omni_python_sdk/api/ai/ai_credit_controls_update.py index aadbcd9..f806eb0 100644 --- a/omni_python_sdk/api/ai/ai_credit_controls_update.py +++ b/omni_python_sdk/api/ai/ai_credit_controls_update.py @@ -79,12 +79,13 @@ def sync_detailed( ) -> Response[AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403]: """Update AI credit controls - Update the organization's AI credit controls: the downgrade and shutoff thresholds and the default - per-user credit limit (userDefaultCredits). All fields are optional and tri-state: omit a field to - leave it unchanged, send `null` to turn that control off (for userDefaultCredits: unlimited by - default), or send a non-negative number to set it. At least one field is required. The - `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the - full current state, the same shape as GET. + Update the organization's AI credit controls: the downgrade and shutoff thresholds, the default per- + user credit limit (userDefaultCredits), and the default per-entity-group credit limit + (entityGroupDefaultCredits). All fields are optional and tri-state: omit a field to leave it + unchanged, send `null` to turn that control off (for the defaults: unlimited by default), or send a + non-negative number to set it. At least one field is required. The `downgradeCredits <= + shutoffCredits` invariant is enforced against the merged result. Returns the full current state, the + same shape as GET. Args: body (AiCreditControlsUpdateBody): @@ -115,12 +116,13 @@ def sync( ) -> AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403 | None: """Update AI credit controls - Update the organization's AI credit controls: the downgrade and shutoff thresholds and the default - per-user credit limit (userDefaultCredits). All fields are optional and tri-state: omit a field to - leave it unchanged, send `null` to turn that control off (for userDefaultCredits: unlimited by - default), or send a non-negative number to set it. At least one field is required. The - `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the - full current state, the same shape as GET. + Update the organization's AI credit controls: the downgrade and shutoff thresholds, the default per- + user credit limit (userDefaultCredits), and the default per-entity-group credit limit + (entityGroupDefaultCredits). All fields are optional and tri-state: omit a field to leave it + unchanged, send `null` to turn that control off (for the defaults: unlimited by default), or send a + non-negative number to set it. At least one field is required. The `downgradeCredits <= + shutoffCredits` invariant is enforced against the merged result. Returns the full current state, the + same shape as GET. Args: body (AiCreditControlsUpdateBody): @@ -146,12 +148,13 @@ async def asyncio_detailed( ) -> Response[AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403]: """Update AI credit controls - Update the organization's AI credit controls: the downgrade and shutoff thresholds and the default - per-user credit limit (userDefaultCredits). All fields are optional and tri-state: omit a field to - leave it unchanged, send `null` to turn that control off (for userDefaultCredits: unlimited by - default), or send a non-negative number to set it. At least one field is required. The - `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the - full current state, the same shape as GET. + Update the organization's AI credit controls: the downgrade and shutoff thresholds, the default per- + user credit limit (userDefaultCredits), and the default per-entity-group credit limit + (entityGroupDefaultCredits). All fields are optional and tri-state: omit a field to leave it + unchanged, send `null` to turn that control off (for the defaults: unlimited by default), or send a + non-negative number to set it. At least one field is required. The `downgradeCredits <= + shutoffCredits` invariant is enforced against the merged result. Returns the full current state, the + same shape as GET. Args: body (AiCreditControlsUpdateBody): @@ -180,12 +183,13 @@ async def asyncio( ) -> AiCreditControlsResponse | ApiError400 | ApiError401 | ApiError403 | None: """Update AI credit controls - Update the organization's AI credit controls: the downgrade and shutoff thresholds and the default - per-user credit limit (userDefaultCredits). All fields are optional and tri-state: omit a field to - leave it unchanged, send `null` to turn that control off (for userDefaultCredits: unlimited by - default), or send a non-negative number to set it. At least one field is required. The - `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the - full current state, the same shape as GET. + Update the organization's AI credit controls: the downgrade and shutoff thresholds, the default per- + user credit limit (userDefaultCredits), and the default per-entity-group credit limit + (entityGroupDefaultCredits). All fields are optional and tri-state: omit a field to leave it + unchanged, send `null` to turn that control off (for the defaults: unlimited by default), or send a + non-negative number to set it. At least one field is required. The `downgradeCredits <= + shutoffCredits` invariant is enforced against the merged result. Returns the full current state, the + same shape as GET. Args: body (AiCreditControlsUpdateBody): diff --git a/omni_python_sdk/api/ai/ai_generate_query.py b/omni_python_sdk/api/ai/ai_generate_query.py index 1543600..6924c01 100644 --- a/omni_python_sdk/api/ai/ai_generate_query.py +++ b/omni_python_sdk/api/ai/ai_generate_query.py @@ -103,7 +103,9 @@ def sync_detailed( Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from - the model, and constructs a query. Requires the querier role on the target model. + the model, and constructs a query. Requires the querier role on the target model. The effective + user's per-connector AI toggles (set in the chat + menu) govern which integration tools the agent + may use. Args: body (AiGenerateQueryBody): @@ -138,7 +140,9 @@ def sync( Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from - the model, and constructs a query. Requires the querier role on the target model. + the model, and constructs a query. Requires the querier role on the target model. The effective + user's per-connector AI toggles (set in the chat + menu) govern which integration tools the agent + may use. Args: body (AiGenerateQueryBody): @@ -168,7 +172,9 @@ async def asyncio_detailed( Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from - the model, and constructs a query. Requires the querier role on the target model. + the model, and constructs a query. Requires the querier role on the target model. The effective + user's per-connector AI toggles (set in the chat + menu) govern which integration tools the agent + may use. Args: body (AiGenerateQueryBody): @@ -201,7 +207,9 @@ async def asyncio( Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from - the model, and constructs a query. Requires the querier role on the target model. + the model, and constructs a query. Requires the querier role on the target model. The effective + user's per-connector AI toggles (set in the chat + menu) govern which integration tools the agent + may use. Args: body (AiGenerateQueryBody): diff --git a/omni_python_sdk/api/ai/ai_job_submit.py b/omni_python_sdk/api/ai/ai_job_submit.py index 78539f1..2deb6ac 100644 --- a/omni_python_sdk/api/ai/ai_job_submit.py +++ b/omni_python_sdk/api/ai/ai_job_submit.py @@ -108,7 +108,8 @@ def sync_detailed( queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. - Optionally continue an existing conversation by providing a conversationId. + Optionally continue an existing conversation by providing a conversationId. The effective user's + per-connector AI toggles (set in the chat + menu) govern which integration tools the agent may use. Args: user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) @@ -146,7 +147,8 @@ def sync( queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. - Optionally continue an existing conversation by providing a conversationId. + Optionally continue an existing conversation by providing a conversationId. The effective user's + per-connector AI toggles (set in the chat + menu) govern which integration tools the agent may use. Args: user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) @@ -179,7 +181,8 @@ async def asyncio_detailed( queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. - Optionally continue an existing conversation by providing a conversationId. + Optionally continue an existing conversation by providing a conversationId. The effective user's + per-connector AI toggles (set in the chat + menu) govern which integration tools the agent may use. Args: user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) @@ -215,7 +218,8 @@ async def asyncio( queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. - Optionally continue an existing conversation by providing a conversationId. + Optionally continue an existing conversation by providing a conversationId. The effective user's + per-connector AI toggles (set in the chat + menu) govern which integration tools the agent may use. Args: user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) diff --git a/omni_python_sdk/api/ai_eval/ai_eval_runs_create.py b/omni_python_sdk/api/ai_eval/ai_eval_runs_create.py index 8df66b7..70036bd 100644 --- a/omni_python_sdk/api/ai_eval/ai_eval_runs_create.py +++ b/omni_python_sdk/api/ai_eval/ai_eval_runs_create.py @@ -140,9 +140,9 @@ def sync_detailed( ]: """Start an eval run - Create and start a new run against an existing prompt set. The run enqueues one agentic job per - prompt and begins executing immediately. Returns the newly created run with its initial per-prompt - result rows. + Create and start a new run against an existing prompt set. The run enqueues + `run_config.repeat_count` agentic jobs per prompt (default 1) and begins executing immediately. + Returns the newly created run with its initial per-execution result rows. Args: body (EvalRunsCreateBody): @@ -184,9 +184,9 @@ def sync( ): """Start an eval run - Create and start a new run against an existing prompt set. The run enqueues one agentic job per - prompt and begins executing immediately. Returns the newly created run with its initial per-prompt - result rows. + Create and start a new run against an existing prompt set. The run enqueues + `run_config.repeat_count` agentic jobs per prompt (default 1) and begins executing immediately. + Returns the newly created run with its initial per-execution result rows. Args: body (EvalRunsCreateBody): @@ -222,9 +222,9 @@ async def asyncio_detailed( ]: """Start an eval run - Create and start a new run against an existing prompt set. The run enqueues one agentic job per - prompt and begins executing immediately. Returns the newly created run with its initial per-prompt - result rows. + Create and start a new run against an existing prompt set. The run enqueues + `run_config.repeat_count` agentic jobs per prompt (default 1) and begins executing immediately. + Returns the newly created run with its initial per-execution result rows. Args: body (EvalRunsCreateBody): @@ -264,9 +264,9 @@ async def asyncio( ): """Start an eval run - Create and start a new run against an existing prompt set. The run enqueues one agentic job per - prompt and begins executing immediately. Returns the newly created run with its initial per-prompt - result rows. + Create and start a new run against an existing prompt set. The run enqueues + `run_config.repeat_count` agentic jobs per prompt (default 1) and begins executing immediately. + Returns the newly created run with its initial per-execution result rows. Args: body (EvalRunsCreateBody): diff --git a/omni_python_sdk/api/ai_model_suggestions/model_suggestions_generate.py b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_generate.py new file mode 100644 index 0000000..a8db4d0 --- /dev/null +++ b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_generate.py @@ -0,0 +1,210 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.generate_suggestions_response import GenerateSuggestionsResponse +from ...models.suggestions_cooldown_response import SuggestionsCooldownResponse +from ...types import Response + + +def _get_kwargs( + model_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "post", + "url": "/api/v1/models/{model_id}/suggestions/generate".format( + model_id=quote(str(model_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | GenerateSuggestionsResponse | SuggestionsCooldownResponse | None: + if response.status_code == 202: + response_202 = GenerateSuggestionsResponse.from_dict(response.json()) + + return response_202 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if response.status_code == 429: + response_429 = SuggestionsCooldownResponse.from_dict(response.json()) + + return response_429 + + if response.status_code == 500: + response_500 = cast(Any, None) + return response_500 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | GenerateSuggestionsResponse | SuggestionsCooldownResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | GenerateSuggestionsResponse | SuggestionsCooldownResponse]: + """Generate model suggestions + + Triggers an AI suggestion generation run for the shared model and enqueues the async job. Poll `GET + /suggestions/runs/{runId}` for status. Requires organization admin permissions. At most one active + run per model; a cooldown applies after a completed run. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | GenerateSuggestionsResponse | SuggestionsCooldownResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | GenerateSuggestionsResponse | SuggestionsCooldownResponse | None: + """Generate model suggestions + + Triggers an AI suggestion generation run for the shared model and enqueues the async job. Poll `GET + /suggestions/runs/{runId}` for status. Requires organization admin permissions. At most one active + run per model; a cooldown applies after a completed run. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | GenerateSuggestionsResponse | SuggestionsCooldownResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | GenerateSuggestionsResponse | SuggestionsCooldownResponse]: + """Generate model suggestions + + Triggers an AI suggestion generation run for the shared model and enqueues the async job. Poll `GET + /suggestions/runs/{runId}` for status. Requires organization admin permissions. At most one active + run per model; a cooldown applies after a completed run. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | GenerateSuggestionsResponse | SuggestionsCooldownResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | GenerateSuggestionsResponse | SuggestionsCooldownResponse | None: + """Generate model suggestions + + Triggers an AI suggestion generation run for the shared model and enqueues the async job. Poll `GET + /suggestions/runs/{runId}` for status. Requires organization admin permissions. At most one active + run per model; a cooldown applies after a completed run. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | GenerateSuggestionsResponse | SuggestionsCooldownResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_model_suggestions/model_suggestions_run_get.py b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_run_get.py new file mode 100644 index 0000000..9884b99 --- /dev/null +++ b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_run_get.py @@ -0,0 +1,198 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.suggestion_run import SuggestionRun +from ...types import Response + + +def _get_kwargs( + model_id: UUID, + run_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/suggestions/runs/{run_id}".format( + model_id=quote(str(model_id), safe=""), + run_id=quote(str(run_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Any | SuggestionRun | None: + if response.status_code == 200: + response_200 = SuggestionRun.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[Any | SuggestionRun]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuggestionRun]: + """Get a generation run + + Returns the status of a specific generation run. Poll until `status` is terminal (`complete` or + `failed`), then re-fetch the suggestions list. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the run belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + run_id (UUID): UUID of the generation run Example: b2c3d4e5-f6a7-8901-bcde-f12345678901. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuggestionRun] + """ + + kwargs = _get_kwargs( + model_id=model_id, + run_id=run_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuggestionRun | None: + """Get a generation run + + Returns the status of a specific generation run. Poll until `status` is terminal (`complete` or + `failed`), then re-fetch the suggestions list. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the run belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + run_id (UUID): UUID of the generation run Example: b2c3d4e5-f6a7-8901-bcde-f12345678901. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuggestionRun + """ + + return sync_detailed( + model_id=model_id, + run_id=run_id, + client=client, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuggestionRun]: + """Get a generation run + + Returns the status of a specific generation run. Poll until `status` is terminal (`complete` or + `failed`), then re-fetch the suggestions list. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the run belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + run_id (UUID): UUID of the generation run Example: b2c3d4e5-f6a7-8901-bcde-f12345678901. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuggestionRun] + """ + + kwargs = _get_kwargs( + model_id=model_id, + run_id=run_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + run_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuggestionRun | None: + """Get a generation run + + Returns the status of a specific generation run. Poll until `status` is terminal (`complete` or + `failed`), then re-fetch the suggestions list. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the run belongs to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + run_id (UUID): UUID of the generation run Example: b2c3d4e5-f6a7-8901-bcde-f12345678901. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuggestionRun + """ + + return ( + await asyncio_detailed( + model_id=model_id, + run_id=run_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_model_suggestions/model_suggestions_run_latest.py b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_run_latest.py new file mode 100644 index 0000000..10938fe --- /dev/null +++ b/omni_python_sdk/api/ai_model_suggestions/model_suggestions_run_latest.py @@ -0,0 +1,188 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote +from uuid import UUID + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.suggestion_run_latest_response import SuggestionRunLatestResponse +from ...types import Response + + +def _get_kwargs( + model_id: UUID, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "get", + "url": "/api/v1/models/{model_id}/suggestions/runs/latest".format( + model_id=quote(str(model_id), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | SuggestionRunLatestResponse | None: + if response.status_code == 200: + response_200 = SuggestionRunLatestResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 400: + response_400 = cast(Any, None) + return response_400 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | SuggestionRunLatestResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuggestionRunLatestResponse]: + """Get the latest generation run + + Returns the most recent generation run for the shared model (the active run if one is in flight, + otherwise the last terminal run), or null if none exists. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuggestionRunLatestResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuggestionRunLatestResponse | None: + """Get the latest generation run + + Returns the most recent generation run for the shared model (the active run if one is in flight, + otherwise the last terminal run), or null if none exists. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuggestionRunLatestResponse + """ + + return sync_detailed( + model_id=model_id, + client=client, + ).parsed + + +async def asyncio_detailed( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | SuggestionRunLatestResponse]: + """Get the latest generation run + + Returns the most recent generation run for the shared model (the active run if one is in flight, + otherwise the last terminal run), or null if none exists. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | SuggestionRunLatestResponse] + """ + + kwargs = _get_kwargs( + model_id=model_id, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + model_id: UUID, + *, + client: AuthenticatedClient | Client, +) -> Any | SuggestionRunLatestResponse | None: + """Get the latest generation run + + Returns the most recent generation run for the shared model (the active run if one is in flight, + otherwise the last terminal run), or null if none exists. Requires organization admin permissions. + + Args: + model_id (UUID): UUID of the shared model the suggestions belong to Example: + a1b2c3d4-e5f6-7890-abcd-ef1234567890. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | SuggestionRunLatestResponse + """ + + return ( + await asyncio_detailed( + model_id=model_id, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/ai_routines/routine_trigger.py b/omni_python_sdk/api/ai_routines/routine_trigger.py index 95ed257..e984e13 100644 --- a/omni_python_sdk/api/ai_routines/routine_trigger.py +++ b/omni_python_sdk/api/ai_routines/routine_trigger.py @@ -102,8 +102,10 @@ def sync_detailed( Run a routine immediately, in addition to its schedule. The run executes once using the routine owner's permissions and delivers the AI response to every configured recipient — it is not a private - preview. Returns once the run has started; the result is delivered asynchronously. Organization API - keys can pass `?userId=` to act on behalf of a specific organization member. + preview. Because runs execute as the owner, the owner's per-connector AI toggles (set in the chat + + menu) govern which integration tools the agent may use. Returns once the run has started; the result + is delivered asynchronously. Organization API keys can pass `?userId=` to act on + behalf of a specific organization member. Args: id (UUID): The UUID of the routine. @@ -139,8 +141,10 @@ def sync( Run a routine immediately, in addition to its schedule. The run executes once using the routine owner's permissions and delivers the AI response to every configured recipient — it is not a private - preview. Returns once the run has started; the result is delivered asynchronously. Organization API - keys can pass `?userId=` to act on behalf of a specific organization member. + preview. Because runs execute as the owner, the owner's per-connector AI toggles (set in the chat + + menu) govern which integration tools the agent may use. Returns once the run has started; the result + is delivered asynchronously. Organization API keys can pass `?userId=` to act on + behalf of a specific organization member. Args: id (UUID): The UUID of the routine. @@ -171,8 +175,10 @@ async def asyncio_detailed( Run a routine immediately, in addition to its schedule. The run executes once using the routine owner's permissions and delivers the AI response to every configured recipient — it is not a private - preview. Returns once the run has started; the result is delivered asynchronously. Organization API - keys can pass `?userId=` to act on behalf of a specific organization member. + preview. Because runs execute as the owner, the owner's per-connector AI toggles (set in the chat + + menu) govern which integration tools the agent may use. Returns once the run has started; the result + is delivered asynchronously. Organization API keys can pass `?userId=` to act on + behalf of a specific organization member. Args: id (UUID): The UUID of the routine. @@ -206,8 +212,10 @@ async def asyncio( Run a routine immediately, in addition to its schedule. The run executes once using the routine owner's permissions and delivers the AI response to every configured recipient — it is not a private - preview. Returns once the run has started; the result is delivered asynchronously. Organization API - keys can pass `?userId=` to act on behalf of a specific organization member. + preview. Because runs execute as the owner, the owner's per-connector AI toggles (set in the chat + + menu) govern which integration tools the agent may use. Returns once the run has started; the result + is delivered asynchronously. Organization API keys can pass `?userId=` to act on + behalf of a specific organization member. Args: id (UUID): The UUID of the routine. diff --git a/omni_python_sdk/api/documents/documents_get_permissions.py b/omni_python_sdk/api/documents/documents_get_permissions.py index e40f3d7..522a31c 100644 --- a/omni_python_sdk/api/documents/documents_get_permissions.py +++ b/omni_python_sdk/api/documents/documents_get_permissions.py @@ -8,18 +8,20 @@ from ... import errors from ...client import AuthenticatedClient, Client from ...models.documents_get_permissions_response import DocumentsGetPermissionsResponse -from ...types import UNSET, Response +from ...types import UNSET, Response, Unset def _get_kwargs( identifier: str, *, - user_id: UUID, + user_id: UUID | Unset = UNSET, ) -> dict[str, Any]: params: dict[str, Any] = {} - json_user_id = str(user_id) + json_user_id: str | Unset = UNSET + if not isinstance(user_id, Unset): + json_user_id = str(user_id) params["userId"] = json_user_id params = {k: v for k, v in params.items() if v is not UNSET and v is not None} @@ -76,14 +78,18 @@ def sync_detailed( identifier: str, *, client: AuthenticatedClient | Client, - user_id: UUID, + user_id: UUID | Unset = UNSET, ) -> Response[Any | DocumentsGetPermissionsResponse]: - """Get document permissions + r"""Get document permissions + + Returns the document-level ability values (the Share dialog \"Abilities\" toggles), plus the + resolved permits for a specific user when `userId` is provided. Args: identifier (str): Document identifier (either document ID or identifier slug) Example: abc123. - user_id (UUID): User membership ID to check permissions for + user_id (UUID | Unset): User membership ID to check permissions for. When omitted, only + the document-level abilities are returned. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -109,14 +115,18 @@ def sync( identifier: str, *, client: AuthenticatedClient | Client, - user_id: UUID, + user_id: UUID | Unset = UNSET, ) -> Any | DocumentsGetPermissionsResponse | None: - """Get document permissions + r"""Get document permissions + + Returns the document-level ability values (the Share dialog \"Abilities\" toggles), plus the + resolved permits for a specific user when `userId` is provided. Args: identifier (str): Document identifier (either document ID or identifier slug) Example: abc123. - user_id (UUID): User membership ID to check permissions for + user_id (UUID | Unset): User membership ID to check permissions for. When omitted, only + the document-level abilities are returned. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -137,14 +147,18 @@ async def asyncio_detailed( identifier: str, *, client: AuthenticatedClient | Client, - user_id: UUID, + user_id: UUID | Unset = UNSET, ) -> Response[Any | DocumentsGetPermissionsResponse]: - """Get document permissions + r"""Get document permissions + + Returns the document-level ability values (the Share dialog \"Abilities\" toggles), plus the + resolved permits for a specific user when `userId` is provided. Args: identifier (str): Document identifier (either document ID or identifier slug) Example: abc123. - user_id (UUID): User membership ID to check permissions for + user_id (UUID | Unset): User membership ID to check permissions for. When omitted, only + the document-level abilities are returned. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. @@ -168,14 +182,18 @@ async def asyncio( identifier: str, *, client: AuthenticatedClient | Client, - user_id: UUID, + user_id: UUID | Unset = UNSET, ) -> Any | DocumentsGetPermissionsResponse | None: - """Get document permissions + r"""Get document permissions + + Returns the document-level ability values (the Share dialog \"Abilities\" toggles), plus the + resolved permits for a specific user when `userId` is provided. Args: identifier (str): Document identifier (either document ID or identifier slug) Example: abc123. - user_id (UUID): User membership ID to check permissions for + user_id (UUID | Unset): User membership ID to check permissions for. When omitted, only + the document-level abilities are returned. Raises: errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. diff --git a/omni_python_sdk/api/documents/documents_v2_get_draft.py b/omni_python_sdk/api/documents/documents_v2_get_draft.py index 2d9d2f5..8d6bed6 100644 --- a/omni_python_sdk/api/documents/documents_v2_get_draft.py +++ b/omni_python_sdk/api/documents/documents_v2_get_draft.py @@ -101,8 +101,8 @@ def sync_detailed( Args: identifier (str): Published document identifier. Example: abc123. - draft_identifier (str): Draft workbook identifier (see `POST - /api/v1/documents/{identifier}/draft`). Example: def456. + draft_identifier (str): Draft workbook identifier (see `PATCH + /api/v2/documents/{identifier}/draft`). Example: def456. pretty (DocumentsV2GetDraftPretty | Unset): Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless. @@ -148,8 +148,8 @@ def sync( Args: identifier (str): Published document identifier. Example: abc123. - draft_identifier (str): Draft workbook identifier (see `POST - /api/v1/documents/{identifier}/draft`). Example: def456. + draft_identifier (str): Draft workbook identifier (see `PATCH + /api/v2/documents/{identifier}/draft`). Example: def456. pretty (DocumentsV2GetDraftPretty | Unset): Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless. @@ -190,8 +190,8 @@ async def asyncio_detailed( Args: identifier (str): Published document identifier. Example: abc123. - draft_identifier (str): Draft workbook identifier (see `POST - /api/v1/documents/{identifier}/draft`). Example: def456. + draft_identifier (str): Draft workbook identifier (see `PATCH + /api/v2/documents/{identifier}/draft`). Example: def456. pretty (DocumentsV2GetDraftPretty | Unset): Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless. @@ -235,8 +235,8 @@ async def asyncio( Args: identifier (str): Published document identifier. Example: abc123. - draft_identifier (str): Draft workbook identifier (see `POST - /api/v1/documents/{identifier}/draft`). Example: def456. + draft_identifier (str): Draft workbook identifier (see `PATCH + /api/v2/documents/{identifier}/draft`). Example: def456. pretty (DocumentsV2GetDraftPretty | Unset): Set `true` or `1` to pretty-print (2-space indent) the response; `false` / `0` (the default) is compact. Key ordering is deterministic regardless. diff --git a/omni_python_sdk/api/documents/documents_v2_patch_draft_by_identifier.py b/omni_python_sdk/api/documents/documents_v2_patch_draft_by_identifier.py index 5bc2f6d..ed8d6f7 100644 --- a/omni_python_sdk/api/documents/documents_v2_patch_draft_by_identifier.py +++ b/omni_python_sdk/api/documents/documents_v2_patch_draft_by_identifier.py @@ -103,8 +103,8 @@ def sync_detailed( Args: identifier (str): Published document identifier. Example: abc123. - draft_identifier (str): Draft workbook identifier (see `POST - /api/v1/documents/{identifier}/draft`). Example: def456. + draft_identifier (str): Draft workbook identifier (see `PATCH + /api/v2/documents/{identifier}/draft`). Example: def456. body (DocumentsV2PatchDraftBody | Unset): Raises: @@ -142,8 +142,8 @@ def sync( Args: identifier (str): Published document identifier. Example: abc123. - draft_identifier (str): Draft workbook identifier (see `POST - /api/v1/documents/{identifier}/draft`). Example: def456. + draft_identifier (str): Draft workbook identifier (see `PATCH + /api/v2/documents/{identifier}/draft`). Example: def456. body (DocumentsV2PatchDraftBody | Unset): Raises: @@ -176,8 +176,8 @@ async def asyncio_detailed( Args: identifier (str): Published document identifier. Example: abc123. - draft_identifier (str): Draft workbook identifier (see `POST - /api/v1/documents/{identifier}/draft`). Example: def456. + draft_identifier (str): Draft workbook identifier (see `PATCH + /api/v2/documents/{identifier}/draft`). Example: def456. body (DocumentsV2PatchDraftBody | Unset): Raises: @@ -213,8 +213,8 @@ async def asyncio( Args: identifier (str): Published document identifier. Example: abc123. - draft_identifier (str): Draft workbook identifier (see `POST - /api/v1/documents/{identifier}/draft`). Example: def456. + draft_identifier (str): Draft workbook identifier (see `PATCH + /api/v2/documents/{identifier}/draft`). Example: def456. body (DocumentsV2PatchDraftBody | Unset): Raises: diff --git a/omni_python_sdk/api/documents/documents_v2_remove_dashboard.py b/omni_python_sdk/api/documents/documents_v2_remove_dashboard.py new file mode 100644 index 0000000..3a5593b --- /dev/null +++ b/omni_python_sdk/api/documents/documents_v2_remove_dashboard.py @@ -0,0 +1,245 @@ +from http import HTTPStatus +from typing import Any, cast +from urllib.parse import quote + +import httpx + +from ... import errors +from ...client import AuthenticatedClient, Client +from ...models.documents_v2_patch_draft_response import DocumentsV2PatchDraftResponse +from ...types import Response + + +def _get_kwargs( + identifier: str, + draft_identifier: str, +) -> dict[str, Any]: + + _kwargs: dict[str, Any] = { + "method": "delete", + "url": "/api/v2/documents/{identifier}/draft/{draft_identifier}/dashboard".format( + identifier=quote(str(identifier), safe=""), + draft_identifier=quote(str(draft_identifier), safe=""), + ), + } + + return _kwargs + + +def _parse_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Any | DocumentsV2PatchDraftResponse | None: + if response.status_code == 200: + response_200 = DocumentsV2PatchDraftResponse.from_dict(response.json()) + + return response_200 + + if response.status_code == 401: + response_401 = cast(Any, None) + return response_401 + + if response.status_code == 403: + response_403 = cast(Any, None) + return response_403 + + if response.status_code == 404: + response_404 = cast(Any, None) + return response_404 + + if response.status_code == 405: + response_405 = cast(Any, None) + return response_405 + + if response.status_code == 409: + response_409 = cast(Any, None) + return response_409 + + if response.status_code == 422: + response_422 = cast(Any, None) + return response_422 + + if client.raise_on_unexpected_status: + raise errors.UnexpectedStatus(response.status_code, response.content) + else: + return None + + +def _build_response( + *, client: AuthenticatedClient | Client, response: httpx.Response +) -> Response[Any | DocumentsV2PatchDraftResponse]: + return Response( + status_code=HTTPStatus(response.status_code), + content=response.content, + headers=response.headers, + parsed=_parse_response(client=client, response=response), + ) + + +def sync_detailed( + identifier: str, + draft_identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | DocumentsV2PatchDraftResponse]: + r"""Remove dashboard from document + + Remove the dashboard from an existing draft, leaving a workbook-only document. Its schedules are + removed too, but at publish time (see below), not on this call. Parity with the UI’s \"Remove + dashboard\" action, and the inverse of adding a dashboard via a `containers` patch. + + Operates only on the draft named by `draftIdentifier`, which the caller creates first via `PATCH + …/draft`. Requiring an explicit draft keeps the removal from silently reusing (and clobbering) a + draft that holds other unpublished work. + + No auto-publish — publish via `POST …/draft/publish` to make the document workbook-only (publishing + also clears the previously-published dashboard’s schedules). Idempotent: a draft that is already + workbook-only returns 200 unchanged. + + Args: + identifier (str): Published document identifier. Example: abc123. + draft_identifier (str): Draft workbook identifier (see `PATCH + /api/v2/documents/{identifier}/draft`). Example: def456. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2PatchDraftResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + draft_identifier=draft_identifier, + ) + + response = client.get_httpx_client().request( + **kwargs, + ) + + return _build_response(client=client, response=response) + + +def sync( + identifier: str, + draft_identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Any | DocumentsV2PatchDraftResponse | None: + r"""Remove dashboard from document + + Remove the dashboard from an existing draft, leaving a workbook-only document. Its schedules are + removed too, but at publish time (see below), not on this call. Parity with the UI’s \"Remove + dashboard\" action, and the inverse of adding a dashboard via a `containers` patch. + + Operates only on the draft named by `draftIdentifier`, which the caller creates first via `PATCH + …/draft`. Requiring an explicit draft keeps the removal from silently reusing (and clobbering) a + draft that holds other unpublished work. + + No auto-publish — publish via `POST …/draft/publish` to make the document workbook-only (publishing + also clears the previously-published dashboard’s schedules). Idempotent: a draft that is already + workbook-only returns 200 unchanged. + + Args: + identifier (str): Published document identifier. Example: abc123. + draft_identifier (str): Draft workbook identifier (see `PATCH + /api/v2/documents/{identifier}/draft`). Example: def456. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2PatchDraftResponse + """ + + return sync_detailed( + identifier=identifier, + draft_identifier=draft_identifier, + client=client, + ).parsed + + +async def asyncio_detailed( + identifier: str, + draft_identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Response[Any | DocumentsV2PatchDraftResponse]: + r"""Remove dashboard from document + + Remove the dashboard from an existing draft, leaving a workbook-only document. Its schedules are + removed too, but at publish time (see below), not on this call. Parity with the UI’s \"Remove + dashboard\" action, and the inverse of adding a dashboard via a `containers` patch. + + Operates only on the draft named by `draftIdentifier`, which the caller creates first via `PATCH + …/draft`. Requiring an explicit draft keeps the removal from silently reusing (and clobbering) a + draft that holds other unpublished work. + + No auto-publish — publish via `POST …/draft/publish` to make the document workbook-only (publishing + also clears the previously-published dashboard’s schedules). Idempotent: a draft that is already + workbook-only returns 200 unchanged. + + Args: + identifier (str): Published document identifier. Example: abc123. + draft_identifier (str): Draft workbook identifier (see `PATCH + /api/v2/documents/{identifier}/draft`). Example: def456. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Response[Any | DocumentsV2PatchDraftResponse] + """ + + kwargs = _get_kwargs( + identifier=identifier, + draft_identifier=draft_identifier, + ) + + response = await client.get_async_httpx_client().request(**kwargs) + + return _build_response(client=client, response=response) + + +async def asyncio( + identifier: str, + draft_identifier: str, + *, + client: AuthenticatedClient | Client, +) -> Any | DocumentsV2PatchDraftResponse | None: + r"""Remove dashboard from document + + Remove the dashboard from an existing draft, leaving a workbook-only document. Its schedules are + removed too, but at publish time (see below), not on this call. Parity with the UI’s \"Remove + dashboard\" action, and the inverse of adding a dashboard via a `containers` patch. + + Operates only on the draft named by `draftIdentifier`, which the caller creates first via `PATCH + …/draft`. Requiring an explicit draft keeps the removal from silently reusing (and clobbering) a + draft that holds other unpublished work. + + No auto-publish — publish via `POST …/draft/publish` to make the document workbook-only (publishing + also clears the previously-published dashboard’s schedules). Idempotent: a draft that is already + workbook-only returns 200 unchanged. + + Args: + identifier (str): Published document identifier. Example: abc123. + draft_identifier (str): Draft workbook identifier (see `PATCH + /api/v2/documents/{identifier}/draft`). Example: def456. + + Raises: + errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True. + httpx.TimeoutException: If the request takes longer than Client.timeout. + + Returns: + Any | DocumentsV2PatchDraftResponse + """ + + return ( + await asyncio_detailed( + identifier=identifier, + draft_identifier=draft_identifier, + client=client, + ) + ).parsed diff --git a/omni_python_sdk/api/models/models_create.py b/omni_python_sdk/api/models/models_create.py index d7ea55b..86c9774 100644 --- a/omni_python_sdk/api/models/models_create.py +++ b/omni_python_sdk/api/models/models_create.py @@ -78,7 +78,9 @@ def sync_detailed( ) -> Response[Any | ModelsCreateModelsCreateResponse]: """Create model - Create a new model. Supports creating schema, shared, branch, and shared_extension models. + Create a new model. Supports creating schema, shared, branch, shared_extension, and query models. A + query model (modelKind QUERY) is created empty under a workbook model (baseModelId); populate its + views and fields via the model YAML endpoint. Args: body (CreateModelSchemaBase | Unset): @@ -109,7 +111,9 @@ def sync( ) -> Any | ModelsCreateModelsCreateResponse | None: """Create model - Create a new model. Supports creating schema, shared, branch, and shared_extension models. + Create a new model. Supports creating schema, shared, branch, shared_extension, and query models. A + query model (modelKind QUERY) is created empty under a workbook model (baseModelId); populate its + views and fields via the model YAML endpoint. Args: body (CreateModelSchemaBase | Unset): @@ -135,7 +139,9 @@ async def asyncio_detailed( ) -> Response[Any | ModelsCreateModelsCreateResponse]: """Create model - Create a new model. Supports creating schema, shared, branch, and shared_extension models. + Create a new model. Supports creating schema, shared, branch, shared_extension, and query models. A + query model (modelKind QUERY) is created empty under a workbook model (baseModelId); populate its + views and fields via the model YAML endpoint. Args: body (CreateModelSchemaBase | Unset): @@ -164,7 +170,9 @@ async def asyncio( ) -> Any | ModelsCreateModelsCreateResponse | None: """Create model - Create a new model. Supports creating schema, shared, branch, and shared_extension models. + Create a new model. Supports creating schema, shared, branch, shared_extension, and query models. A + query model (modelKind QUERY) is created empty under a workbook model (baseModelId); populate its + views and fields via the model YAML endpoint. Args: body (CreateModelSchemaBase | Unset): diff --git a/omni_python_sdk/api/models/models_git_create.py b/omni_python_sdk/api/models/models_git_create.py index 9be4ed4..5ca09fc 100644 --- a/omni_python_sdk/api/models/models_git_create.py +++ b/omni_python_sdk/api/models/models_git_create.py @@ -88,6 +88,9 @@ def sync_detailed( ) -> Response[Any | ModelsGitCreateResponse]: """Create git configuration + Create git configuration for a model. For SSH auth, Omni generates a deploy keypair by default; + supply deployPrivateKey (with deployKeyPassphrase for encrypted keys) to bring your own instead. + Args: model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. body (ModelsGitCreateBody | Unset): @@ -120,6 +123,9 @@ def sync( ) -> Any | ModelsGitCreateResponse | None: """Create git configuration + Create git configuration for a model. For SSH auth, Omni generates a deploy keypair by default; + supply deployPrivateKey (with deployKeyPassphrase for encrypted keys) to bring your own instead. + Args: model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. body (ModelsGitCreateBody | Unset): @@ -147,6 +153,9 @@ async def asyncio_detailed( ) -> Response[Any | ModelsGitCreateResponse]: """Create git configuration + Create git configuration for a model. For SSH auth, Omni generates a deploy keypair by default; + supply deployPrivateKey (with deployKeyPassphrase for encrypted keys) to bring your own instead. + Args: model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. body (ModelsGitCreateBody | Unset): @@ -177,6 +186,9 @@ async def asyncio( ) -> Any | ModelsGitCreateResponse | None: """Create git configuration + Create git configuration for a model. For SSH auth, Omni generates a deploy keypair by default; + supply deployPrivateKey (with deployKeyPassphrase for encrypted keys) to bring your own instead. + Args: model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. body (ModelsGitCreateBody | Unset): diff --git a/omni_python_sdk/api/models/models_git_update.py b/omni_python_sdk/api/models/models_git_update.py index c4e1a7f..e7697ce 100644 --- a/omni_python_sdk/api/models/models_git_update.py +++ b/omni_python_sdk/api/models/models_git_update.py @@ -84,6 +84,11 @@ def sync_detailed( ) -> Response[Any | ModelsGitUpdateResponse]: """Update git configuration + Update git configuration for a model. Only provided fields are changed. For SSH auth, a bring-your- + own deploy key can be set via deployPrivateKey (with deployKeyPassphrase for encrypted keys), + enabling zero-downtime key rotation: authorize the matching public key with the git provider first, + then set the key here. + Args: model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. body (ModelsGitUpdateBody | Unset): @@ -116,6 +121,11 @@ def sync( ) -> Any | ModelsGitUpdateResponse | None: """Update git configuration + Update git configuration for a model. Only provided fields are changed. For SSH auth, a bring-your- + own deploy key can be set via deployPrivateKey (with deployKeyPassphrase for encrypted keys), + enabling zero-downtime key rotation: authorize the matching public key with the git provider first, + then set the key here. + Args: model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. body (ModelsGitUpdateBody | Unset): @@ -143,6 +153,11 @@ async def asyncio_detailed( ) -> Response[Any | ModelsGitUpdateResponse]: """Update git configuration + Update git configuration for a model. Only provided fields are changed. For SSH auth, a bring-your- + own deploy key can be set via deployPrivateKey (with deployKeyPassphrase for encrypted keys), + enabling zero-downtime key rotation: authorize the matching public key with the git provider first, + then set the key here. + Args: model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. body (ModelsGitUpdateBody | Unset): @@ -173,6 +188,11 @@ async def asyncio( ) -> Any | ModelsGitUpdateResponse | None: """Update git configuration + Update git configuration for a model. Only provided fields are changed. For SSH auth, a bring-your- + own deploy key can be set via deployPrivateKey (with deployKeyPassphrase for encrypted keys), + enabling zero-downtime key rotation: authorize the matching public key with the git provider first, + then set the key here. + Args: model_id (UUID): Model UUID Example: 123e4567-e89b-12d3-a456-426614174000. body (ModelsGitUpdateBody | Unset): diff --git a/omni_python_sdk/api/query/query_run.py b/omni_python_sdk/api/query/query_run.py index 3156e03..0ebac7a 100644 --- a/omni_python_sdk/api/query/query_run.py +++ b/omni_python_sdk/api/query/query_run.py @@ -7,7 +7,7 @@ from ... import errors from ...client import AuthenticatedClient, Client from ...models.query_run_body import QueryRunBody -from ...models.query_run_response import QueryRunResponse +from ...models.query_run_response_200_item import QueryRunResponse200Item from ...models.query_timeout_response import QueryTimeoutResponse from ...types import UNSET, Response, Unset @@ -45,9 +45,14 @@ def _get_kwargs( def _parse_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Any | QueryRunResponse | QueryTimeoutResponse | None: +) -> Any | QueryTimeoutResponse | list[QueryRunResponse200Item] | None: if response.status_code == 200: - response_200 = QueryRunResponse.from_dict(response.json()) + response_200 = [] + _response_200 = response.json() + for response_200_item_data in _response_200: + response_200_item = QueryRunResponse200Item.from_dict(response_200_item_data) + + response_200.append(response_200_item) return response_200 @@ -84,7 +89,7 @@ def _parse_response( def _build_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[Any | QueryRunResponse | QueryTimeoutResponse]: +) -> Response[Any | QueryTimeoutResponse | list[QueryRunResponse200Item]]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -98,9 +103,18 @@ def sync_detailed( client: AuthenticatedClient | Client, body: QueryRunBody | Unset = UNSET, user_id: UUID | Unset = UNSET, -) -> Response[Any | QueryRunResponse | QueryTimeoutResponse]: +) -> Response[Any | QueryTimeoutResponse | list[QueryRunResponse200Item]]: """Execute a semantic query + Runs a semantic query. By default (no `resultType`) the response is a stream of newline-delimited + JSON (`Content-Type: text/ndjson`), one JSON object per line: a `jobs_submitted` header, then one + line per job as it reaches a terminal state (a completed job carries the result set as + base64-encoded Arrow IPC in `result`; use `summary.fields` to interpret the decoded columns), then a + footer. A footer with non-empty `remaining_job_ids` means the wait window elapsed before every job + finished — poll GET /api/v1/query/wait with those IDs until the list is empty. When `resultType` is + set, the response is instead a single CSV, XLSX, or JSON document, and a timeout is reported as a + 408. + Args: user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) body (QueryRunBody | Unset): @@ -110,7 +124,7 @@ def sync_detailed( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Any | QueryRunResponse | QueryTimeoutResponse] + Response[Any | QueryTimeoutResponse | list[QueryRunResponse200Item]] """ kwargs = _get_kwargs( @@ -130,9 +144,18 @@ def sync( client: AuthenticatedClient | Client, body: QueryRunBody | Unset = UNSET, user_id: UUID | Unset = UNSET, -) -> Any | QueryRunResponse | QueryTimeoutResponse | None: +) -> Any | QueryTimeoutResponse | list[QueryRunResponse200Item] | None: """Execute a semantic query + Runs a semantic query. By default (no `resultType`) the response is a stream of newline-delimited + JSON (`Content-Type: text/ndjson`), one JSON object per line: a `jobs_submitted` header, then one + line per job as it reaches a terminal state (a completed job carries the result set as + base64-encoded Arrow IPC in `result`; use `summary.fields` to interpret the decoded columns), then a + footer. A footer with non-empty `remaining_job_ids` means the wait window elapsed before every job + finished — poll GET /api/v1/query/wait with those IDs until the list is empty. When `resultType` is + set, the response is instead a single CSV, XLSX, or JSON document, and a timeout is reported as a + 408. + Args: user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) body (QueryRunBody | Unset): @@ -142,7 +165,7 @@ def sync( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Any | QueryRunResponse | QueryTimeoutResponse + Any | QueryTimeoutResponse | list[QueryRunResponse200Item] """ return sync_detailed( @@ -157,9 +180,18 @@ async def asyncio_detailed( client: AuthenticatedClient | Client, body: QueryRunBody | Unset = UNSET, user_id: UUID | Unset = UNSET, -) -> Response[Any | QueryRunResponse | QueryTimeoutResponse]: +) -> Response[Any | QueryTimeoutResponse | list[QueryRunResponse200Item]]: """Execute a semantic query + Runs a semantic query. By default (no `resultType`) the response is a stream of newline-delimited + JSON (`Content-Type: text/ndjson`), one JSON object per line: a `jobs_submitted` header, then one + line per job as it reaches a terminal state (a completed job carries the result set as + base64-encoded Arrow IPC in `result`; use `summary.fields` to interpret the decoded columns), then a + footer. A footer with non-empty `remaining_job_ids` means the wait window elapsed before every job + finished — poll GET /api/v1/query/wait with those IDs until the list is empty. When `resultType` is + set, the response is instead a single CSV, XLSX, or JSON document, and a timeout is reported as a + 408. + Args: user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) body (QueryRunBody | Unset): @@ -169,7 +201,7 @@ async def asyncio_detailed( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Any | QueryRunResponse | QueryTimeoutResponse] + Response[Any | QueryTimeoutResponse | list[QueryRunResponse200Item]] """ kwargs = _get_kwargs( @@ -187,9 +219,18 @@ async def asyncio( client: AuthenticatedClient | Client, body: QueryRunBody | Unset = UNSET, user_id: UUID | Unset = UNSET, -) -> Any | QueryRunResponse | QueryTimeoutResponse | None: +) -> Any | QueryTimeoutResponse | list[QueryRunResponse200Item] | None: """Execute a semantic query + Runs a semantic query. By default (no `resultType`) the response is a stream of newline-delimited + JSON (`Content-Type: text/ndjson`), one JSON object per line: a `jobs_submitted` header, then one + line per job as it reaches a terminal state (a completed job carries the result set as + base64-encoded Arrow IPC in `result`; use `summary.fields` to interpret the decoded columns), then a + footer. A footer with non-empty `remaining_job_ids` means the wait window elapsed before every job + finished — poll GET /api/v1/query/wait with those IDs until the list is empty. When `resultType` is + set, the response is instead a single CSV, XLSX, or JSON document, and a timeout is reported as a + 408. + Args: user_id (UUID | Unset): Target user membership ID (for org-scoped API keys) body (QueryRunBody | Unset): @@ -199,7 +240,7 @@ async def asyncio( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Any | QueryRunResponse | QueryTimeoutResponse + Any | QueryTimeoutResponse | list[QueryRunResponse200Item] """ return ( diff --git a/omni_python_sdk/api/query/query_wait.py b/omni_python_sdk/api/query/query_wait.py index 41c0ef3..d46a836 100644 --- a/omni_python_sdk/api/query/query_wait.py +++ b/omni_python_sdk/api/query/query_wait.py @@ -5,7 +5,8 @@ from ... import errors from ...client import AuthenticatedClient, Client -from ...models.query_wait_response import QueryWaitResponse +from ...models.query_stream_footer_line import QueryStreamFooterLine +from ...models.query_stream_job_line import QueryStreamJobLine from ...types import UNSET, Response @@ -31,9 +32,25 @@ def _get_kwargs( def _parse_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Any | QueryWaitResponse | None: +) -> Any | QueryStreamFooterLine | QueryStreamJobLine | None: if response.status_code == 200: - response_200 = QueryWaitResponse.from_dict(response.json()) + + def _parse_response_200(data: object) -> QueryStreamFooterLine | QueryStreamJobLine: + try: + if not isinstance(data, dict): + raise TypeError() + componentsschemas_query_wait_stream_line_type_0 = QueryStreamJobLine.from_dict(data) + + return componentsschemas_query_wait_stream_line_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + if not isinstance(data, dict): + raise TypeError() + componentsschemas_query_wait_stream_line_type_1 = QueryStreamFooterLine.from_dict(data) + + return componentsschemas_query_wait_stream_line_type_1 + + response_200 = _parse_response_200(response.text) return response_200 @@ -61,7 +78,7 @@ def _parse_response( def _build_response( *, client: AuthenticatedClient | Client, response: httpx.Response -) -> Response[Any | QueryWaitResponse]: +) -> Response[Any | QueryStreamFooterLine | QueryStreamJobLine]: return Response( status_code=HTTPStatus(response.status_code), content=response.content, @@ -74,9 +91,15 @@ def sync_detailed( *, client: AuthenticatedClient | Client, job_ids: str, -) -> Response[Any | QueryWaitResponse]: +) -> Response[Any | QueryStreamFooterLine | QueryStreamJobLine]: """Wait for query jobs to complete + Waits for previously submitted query jobs and streams results as they complete. The response is a + stream of newline-delimited JSON (`Content-Type: text/ndjson`): one line per job (same shape as the + job lines from query/run, including the base64-encoded Arrow IPC `result`), then a footer. Unlike + query/run, there is no `jobs_submitted` header line. If the footer's `remaining_job_ids` is non- + empty, call this endpoint again with those IDs until it is empty. + Args: job_ids (str): Comma-separated list of job IDs to wait for. Obtained from the query/run response. Example: job_abc123,job_def456. @@ -86,7 +109,7 @@ def sync_detailed( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Any | QueryWaitResponse] + Response[Any | QueryStreamFooterLine | QueryStreamJobLine] """ kwargs = _get_kwargs( @@ -104,9 +127,15 @@ def sync( *, client: AuthenticatedClient | Client, job_ids: str, -) -> Any | QueryWaitResponse | None: +) -> Any | QueryStreamFooterLine | QueryStreamJobLine | None: """Wait for query jobs to complete + Waits for previously submitted query jobs and streams results as they complete. The response is a + stream of newline-delimited JSON (`Content-Type: text/ndjson`): one line per job (same shape as the + job lines from query/run, including the base64-encoded Arrow IPC `result`), then a footer. Unlike + query/run, there is no `jobs_submitted` header line. If the footer's `remaining_job_ids` is non- + empty, call this endpoint again with those IDs until it is empty. + Args: job_ids (str): Comma-separated list of job IDs to wait for. Obtained from the query/run response. Example: job_abc123,job_def456. @@ -116,7 +145,7 @@ def sync( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Any | QueryWaitResponse + Any | QueryStreamFooterLine | QueryStreamJobLine """ return sync_detailed( @@ -129,9 +158,15 @@ async def asyncio_detailed( *, client: AuthenticatedClient | Client, job_ids: str, -) -> Response[Any | QueryWaitResponse]: +) -> Response[Any | QueryStreamFooterLine | QueryStreamJobLine]: """Wait for query jobs to complete + Waits for previously submitted query jobs and streams results as they complete. The response is a + stream of newline-delimited JSON (`Content-Type: text/ndjson`): one line per job (same shape as the + job lines from query/run, including the base64-encoded Arrow IPC `result`), then a footer. Unlike + query/run, there is no `jobs_submitted` header line. If the footer's `remaining_job_ids` is non- + empty, call this endpoint again with those IDs until it is empty. + Args: job_ids (str): Comma-separated list of job IDs to wait for. Obtained from the query/run response. Example: job_abc123,job_def456. @@ -141,7 +176,7 @@ async def asyncio_detailed( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Response[Any | QueryWaitResponse] + Response[Any | QueryStreamFooterLine | QueryStreamJobLine] """ kwargs = _get_kwargs( @@ -157,9 +192,15 @@ async def asyncio( *, client: AuthenticatedClient | Client, job_ids: str, -) -> Any | QueryWaitResponse | None: +) -> Any | QueryStreamFooterLine | QueryStreamJobLine | None: """Wait for query jobs to complete + Waits for previously submitted query jobs and streams results as they complete. The response is a + stream of newline-delimited JSON (`Content-Type: text/ndjson`): one line per job (same shape as the + job lines from query/run, including the base64-encoded Arrow IPC `result`), then a footer. Unlike + query/run, there is no `jobs_submitted` header line. If the footer's `remaining_job_ids` is non- + empty, call this endpoint again with those IDs until it is empty. + Args: job_ids (str): Comma-separated list of job IDs to wait for. Obtained from the query/run response. Example: job_abc123,job_def456. @@ -169,7 +210,7 @@ async def asyncio( httpx.TimeoutException: If the request takes longer than Client.timeout. Returns: - Any | QueryWaitResponse + Any | QueryStreamFooterLine | QueryStreamJobLine """ return ( diff --git a/omni_python_sdk/models/__init__.py b/omni_python_sdk/models/__init__.py index 664aeeb..3d00f19 100644 --- a/omni_python_sdk/models/__init__.py +++ b/omni_python_sdk/models/__init__.py @@ -1,5 +1,6 @@ """Contains all the data models used in inputs/outputs""" +from .agentic_job_attachment import AgenticJobAttachment from .ai_agent_action import AiAgentAction from .ai_agent_action_kind import AiAgentActionKind from .ai_agent_actions_response import AiAgentActionsResponse @@ -9,12 +10,20 @@ from .ai_conversation_message import AiConversationMessage from .ai_conversation_message_role import AiConversationMessageRole from .ai_conversations_list_response import AiConversationsListResponse +from .ai_credit_controls_entity_groups_list_response import AiCreditControlsEntityGroupsListResponse +from .ai_credit_controls_entity_groups_list_response_records_item import ( + AiCreditControlsEntityGroupsListResponseRecordsItem, +) from .ai_credit_controls_response import AiCreditControlsResponse from .ai_credit_controls_update_body import AiCreditControlsUpdateBody from .ai_credit_controls_users_list_response import AiCreditControlsUsersListResponse from .ai_credit_controls_users_list_response_records_item import AiCreditControlsUsersListResponseRecordsItem from .ai_credit_shutoff_error import AiCreditShutoffError from .ai_credit_shutoff_error_code import AiCreditShutoffErrorCode +from .ai_entity_group_credit_limit_entry import AiEntityGroupCreditLimitEntry +from .ai_entity_group_credit_limits_response import AiEntityGroupCreditLimitsResponse +from .ai_entity_group_credit_limits_response_entity_groups_item import AiEntityGroupCreditLimitsResponseEntityGroupsItem +from .ai_entity_group_credit_limits_update_body import AiEntityGroupCreditLimitsUpdateBody from .ai_eval_prompt_sets_list_archived import AiEvalPromptSetsListArchived from .ai_eval_runs_list_archived import AiEvalRunsListArchived from .ai_generate_query_body import AiGenerateQueryBody @@ -194,6 +203,7 @@ from .create_model_schema_base_model_kind_type_1 import CreateModelSchemaBaseModelKindType1 from .create_model_schema_base_model_kind_type_2 import CreateModelSchemaBaseModelKindType2 from .create_model_schema_base_model_kind_type_3 import CreateModelSchemaBaseModelKindType3 +from .create_model_schema_base_model_kind_type_4 import CreateModelSchemaBaseModelKindType4 from .dashboard_filters_response import DashboardFiltersResponse from .dashboards_download_body import DashboardsDownloadBody from .dashboards_download_body_format import DashboardsDownloadBodyFormat @@ -222,6 +232,7 @@ from .dbt_exposure_type import DbtExposureType from .dbt_exposure_with_meta import DbtExposureWithMeta from .document import Document +from .document_abilities import DocumentAbilities from .document_count import DocumentCount from .document_export_response import DocumentExportResponse from .document_export_response_document import DocumentExportResponseDocument @@ -367,6 +378,8 @@ from .folders_update_permissions_body_role import FoldersUpdatePermissionsBodyRole from .folders_update_permissions_response import FoldersUpdatePermissionsResponse from .folders_update_response import FoldersUpdateResponse +from .generate_suggestions_response import GenerateSuggestionsResponse +from .generate_suggestions_response_status import GenerateSuggestionsResponseStatus from .grid_container import GridContainer from .ignore_suggestion_body import IgnoreSuggestionBody from .internal_folder_type_0 import InternalFolderType0 @@ -479,9 +492,16 @@ from .query_run_body import QueryRunBody from .query_run_body_cache import QueryRunBodyCache from .query_run_body_result_type import QueryRunBodyResultType -from .query_run_response import QueryRunResponse +from .query_run_response_200_item import QueryRunResponse200Item +from .query_stream_footer_line import QueryStreamFooterLine +from .query_stream_footer_line_timed_out import QueryStreamFooterLineTimedOut +from .query_stream_job_line import QueryStreamJobLine +from .query_stream_job_line_column_name_mapping import QueryStreamJobLineColumnNameMapping +from .query_stream_job_line_stream_stats import QueryStreamJobLineStreamStats +from .query_stream_job_line_used_keys import QueryStreamJobLineUsedKeys +from .query_stream_jobs_submitted_line import QueryStreamJobsSubmittedLine +from .query_stream_jobs_submitted_line_jobs_submitted import QueryStreamJobsSubmittedLineJobsSubmitted from .query_timeout_response import QueryTimeoutResponse -from .query_wait_response import QueryWaitResponse from .reference_container import ReferenceContainer from .role_assignment_result import RoleAssignmentResult from .role_origin_type_0 import RoleOriginType0 @@ -617,6 +637,14 @@ from .suggestion_evidence_item_type import SuggestionEvidenceItemType from .suggestion_proposed_changes import SuggestionProposedChanges from .suggestion_proposed_changes_kind import SuggestionProposedChangesKind +from .suggestion_run import SuggestionRun +from .suggestion_run_error_type_0 import SuggestionRunErrorType0 +from .suggestion_run_latest_response import SuggestionRunLatestResponse +from .suggestion_run_latest_response_run import SuggestionRunLatestResponseRun +from .suggestion_run_status import SuggestionRunStatus +from .suggestion_run_trigger_source import SuggestionRunTriggerSource +from .suggestion_run_triggered_by_type_0 import SuggestionRunTriggeredByType0 +from .suggestions_cooldown_response import SuggestionsCooldownResponse from .upload import Upload from .upload_create_body import UploadCreateBody from .upload_create_response import UploadCreateResponse @@ -664,6 +692,7 @@ from .whoami_user import WhoamiUser __all__ = ( + "AgenticJobAttachment", "AiAgentAction", "AiAgentActionKind", "AiAgentActionsResponse", @@ -673,12 +702,18 @@ "AiConversationMessage", "AiConversationMessageRole", "AiConversationsListResponse", + "AiCreditControlsEntityGroupsListResponse", + "AiCreditControlsEntityGroupsListResponseRecordsItem", "AiCreditControlsResponse", "AiCreditControlsUpdateBody", "AiCreditControlsUsersListResponse", "AiCreditControlsUsersListResponseRecordsItem", "AiCreditShutoffError", "AiCreditShutoffErrorCode", + "AiEntityGroupCreditLimitEntry", + "AiEntityGroupCreditLimitsResponse", + "AiEntityGroupCreditLimitsResponseEntityGroupsItem", + "AiEntityGroupCreditLimitsUpdateBody", "AiEvalPromptSetsListArchived", "AiEvalRunsListArchived", "AiGenerateQueryBody", @@ -822,6 +857,7 @@ "CreateModelSchemaBaseModelKindType1", "CreateModelSchemaBaseModelKindType2", "CreateModelSchemaBaseModelKindType3", + "CreateModelSchemaBaseModelKindType4", "DashboardFiltersResponse", "DashboardsDownloadBody", "DashboardsDownloadBodyFormat", @@ -846,6 +882,7 @@ "DbtExposureType", "DbtExposureWithMeta", "Document", + "DocumentAbilities", "DocumentCount", "DocumentExportResponse", "DocumentExportResponseDocument", @@ -989,6 +1026,8 @@ "FoldersUpdatePermissionsBodyRole", "FoldersUpdatePermissionsResponse", "FoldersUpdateResponse", + "GenerateSuggestionsResponse", + "GenerateSuggestionsResponseStatus", "GridContainer", "IgnoreSuggestionBody", "InternalFolderType0", @@ -1099,9 +1138,16 @@ "QueryRunBody", "QueryRunBodyCache", "QueryRunBodyResultType", - "QueryRunResponse", + "QueryRunResponse200Item", + "QueryStreamFooterLine", + "QueryStreamFooterLineTimedOut", + "QueryStreamJobLine", + "QueryStreamJobLineColumnNameMapping", + "QueryStreamJobLineStreamStats", + "QueryStreamJobLineUsedKeys", + "QueryStreamJobsSubmittedLine", + "QueryStreamJobsSubmittedLineJobsSubmitted", "QueryTimeoutResponse", - "QueryWaitResponse", "ReferenceContainer", "RoleAssignmentResult", "RoleOriginType0", @@ -1219,6 +1265,14 @@ "SuggestionEvidenceItemType", "SuggestionProposedChanges", "SuggestionProposedChangesKind", + "SuggestionRun", + "SuggestionRunErrorType0", + "SuggestionRunLatestResponse", + "SuggestionRunLatestResponseRun", + "SuggestionRunStatus", + "SuggestionRunTriggeredByType0", + "SuggestionRunTriggerSource", + "SuggestionsCooldownResponse", "Upload", "UploadCreateBody", "UploadCreateResponse", diff --git a/omni_python_sdk/models/agentic_job_attachment.py b/omni_python_sdk/models/agentic_job_attachment.py new file mode 100644 index 0000000..b55782b --- /dev/null +++ b/omni_python_sdk/models/agentic_job_attachment.py @@ -0,0 +1,81 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="AgenticJobAttachment") + + +@_attrs_define +class AgenticJobAttachment: + """ + Attributes: + data (str): Base64-encoded file content. Example: iVBORw0KGgoAAAANSUhEUgAA.... + mime_type (str): MIME type of the attachment. Must be an image type (e.g. image/png, image/jpeg) or + application/pdf. Example: image/png. + name (str | Unset): Optional filename, used for display/logging only. Example: legacy-dashboard-screenshot.png. + """ + + data: str + mime_type: str + name: str | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + data = self.data + + mime_type = self.mime_type + + name = self.name + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "data": data, + "mimeType": mime_type, + } + ) + if name is not UNSET: + field_dict["name"] = name + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + data = d.pop("data") + + mime_type = d.pop("mimeType") + + name = d.pop("name", UNSET) + + agentic_job_attachment = cls( + data=data, + mime_type=mime_type, + name=name, + ) + + agentic_job_attachment.additional_properties = d + return agentic_job_attachment + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_credit_controls_entity_groups_list_response.py b/omni_python_sdk/models/ai_credit_controls_entity_groups_list_response.py new file mode 100644 index 0000000..237da03 --- /dev/null +++ b/omni_python_sdk/models/ai_credit_controls_entity_groups_list_response.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.ai_credit_controls_entity_groups_list_response_records_item import ( + AiCreditControlsEntityGroupsListResponseRecordsItem, + ) + from ..models.page_info import PageInfo + + +T = TypeVar("T", bound="AiCreditControlsEntityGroupsListResponse") + + +@_attrs_define +class AiCreditControlsEntityGroupsListResponse: + """ + Attributes: + page_info (PageInfo): + records (list[AiCreditControlsEntityGroupsListResponseRecordsItem]): Entity groups with an individual AI credit + limit, ordered by the entity group id. + """ + + page_info: PageInfo + records: list[AiCreditControlsEntityGroupsListResponseRecordsItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + page_info = self.page_info.to_dict() + + records = [] + for records_item_data in self.records: + records_item = records_item_data.to_dict() + records.append(records_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "pageInfo": page_info, + "records": records, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_credit_controls_entity_groups_list_response_records_item import ( + AiCreditControlsEntityGroupsListResponseRecordsItem, + ) + from ..models.page_info import PageInfo + + d = dict(src_dict) + page_info = PageInfo.from_dict(d.pop("pageInfo")) + + records = [] + _records = d.pop("records") + for records_item_data in _records: + records_item = AiCreditControlsEntityGroupsListResponseRecordsItem.from_dict(records_item_data) + + records.append(records_item) + + ai_credit_controls_entity_groups_list_response = cls( + page_info=page_info, + records=records, + ) + + ai_credit_controls_entity_groups_list_response.additional_properties = d + return ai_credit_controls_entity_groups_list_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_credit_controls_entity_groups_list_response_records_item.py b/omni_python_sdk/models/ai_credit_controls_entity_groups_list_response_records_item.py new file mode 100644 index 0000000..9647cbf --- /dev/null +++ b/omni_python_sdk/models/ai_credit_controls_entity_groups_list_response_records_item.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiCreditControlsEntityGroupsListResponseRecordsItem") + + +@_attrs_define +class AiCreditControlsEntityGroupsListResponseRecordsItem: + """ + Attributes: + credit_limit (float | None): The entity group's individual AI credit limit, or `null` for an explicit unlimited + override. Example: 50. + entity (str): The embed entity's identifier (the SSO `entity` value). Example: acme-corp. + """ + + credit_limit: float | None + entity: str + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + credit_limit: float | None + credit_limit = self.credit_limit + + entity = self.entity + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "creditLimit": credit_limit, + "entity": entity, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_credit_limit(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + credit_limit = _parse_credit_limit(d.pop("creditLimit")) + + entity = d.pop("entity") + + ai_credit_controls_entity_groups_list_response_records_item = cls( + credit_limit=credit_limit, + entity=entity, + ) + + ai_credit_controls_entity_groups_list_response_records_item.additional_properties = d + return ai_credit_controls_entity_groups_list_response_records_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_credit_controls_response.py b/omni_python_sdk/models/ai_credit_controls_response.py index 4db93ab..0b76dea 100644 --- a/omni_python_sdk/models/ai_credit_controls_response.py +++ b/omni_python_sdk/models/ai_credit_controls_response.py @@ -17,6 +17,8 @@ class AiCreditControlsResponse: the same Salesforce account), not just this org. 0 when no limit is configured. Example: 2000. credits_used (float): This org's credit usage in the current billing period. Example: 450. downgrade_credits (float | None): Downgrade threshold, or `null` if the downgrade control is off. Example: 800. + entity_group_default_credits (float | None): Default per-entity-group AI credit limit, or `null` when embed + entity groups are unlimited by default. Example: 100. period_end (int): End of the current billing period as a Unix ms timestamp (UTC calendar-month boundary). period_start (int): Start of the current billing period as a Unix ms timestamp (UTC calendar-month boundary). shutoff_credits (float | None): Shutoff threshold, or `null` if the shutoff control is off. Example: 1200. @@ -27,6 +29,7 @@ class AiCreditControlsResponse: account_credit_limit: float credits_used: float downgrade_credits: float | None + entity_group_default_credits: float | None period_end: int period_start: int shutoff_credits: float | None @@ -41,6 +44,9 @@ def to_dict(self) -> dict[str, Any]: downgrade_credits: float | None downgrade_credits = self.downgrade_credits + entity_group_default_credits: float | None + entity_group_default_credits = self.entity_group_default_credits + period_end = self.period_end period_start = self.period_start @@ -58,6 +64,7 @@ def to_dict(self) -> dict[str, Any]: "accountCreditLimit": account_credit_limit, "creditsUsed": credits_used, "downgradeCredits": downgrade_credits, + "entityGroupDefaultCredits": entity_group_default_credits, "periodEnd": period_end, "periodStart": period_start, "shutoffCredits": shutoff_credits, @@ -81,6 +88,13 @@ def _parse_downgrade_credits(data: object) -> float | None: downgrade_credits = _parse_downgrade_credits(d.pop("downgradeCredits")) + def _parse_entity_group_default_credits(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + entity_group_default_credits = _parse_entity_group_default_credits(d.pop("entityGroupDefaultCredits")) + period_end = d.pop("periodEnd") period_start = d.pop("periodStart") @@ -103,6 +117,7 @@ def _parse_user_default_credits(data: object) -> float | None: account_credit_limit=account_credit_limit, credits_used=credits_used, downgrade_credits=downgrade_credits, + entity_group_default_credits=entity_group_default_credits, period_end=period_end, period_start=period_start, shutoff_credits=shutoff_credits, diff --git a/omni_python_sdk/models/ai_credit_controls_update_body.py b/omni_python_sdk/models/ai_credit_controls_update_body.py index bd78656..786be5b 100644 --- a/omni_python_sdk/models/ai_credit_controls_update_body.py +++ b/omni_python_sdk/models/ai_credit_controls_update_body.py @@ -17,6 +17,9 @@ class AiCreditControlsUpdateBody: downgrade_credits (float | None | Unset): Credit usage at which AI downgrades to a cheaper model. Omit to leave unchanged, `null` to turn off, or a non-negative number to set. Must be at or below shutoffCredits. Example: 800. + entity_group_default_credits (float | None | Unset): Default per-entity-group AI credit limit for the billing + period — what every embed entity group without an individual limit gets. Omit to leave unchanged, `null` for + unlimited by default, or a non-negative number to set. Example: 100. shutoff_credits (float | None | Unset): Credit usage at which AI shuts off entirely. Omit to leave unchanged, `null` to turn off, or a non-negative number to set. Example: 1200. user_default_credits (float | None | Unset): Default per-user AI credit limit for the billing period — what @@ -25,6 +28,7 @@ class AiCreditControlsUpdateBody: """ downgrade_credits: float | None | Unset = UNSET + entity_group_default_credits: float | None | Unset = UNSET shutoff_credits: float | None | Unset = UNSET user_default_credits: float | None | Unset = UNSET @@ -35,6 +39,12 @@ def to_dict(self) -> dict[str, Any]: else: downgrade_credits = self.downgrade_credits + entity_group_default_credits: float | None | Unset + if isinstance(self.entity_group_default_credits, Unset): + entity_group_default_credits = UNSET + else: + entity_group_default_credits = self.entity_group_default_credits + shutoff_credits: float | None | Unset if isinstance(self.shutoff_credits, Unset): shutoff_credits = UNSET @@ -52,6 +62,8 @@ def to_dict(self) -> dict[str, Any]: field_dict.update({}) if downgrade_credits is not UNSET: field_dict["downgradeCredits"] = downgrade_credits + if entity_group_default_credits is not UNSET: + field_dict["entityGroupDefaultCredits"] = entity_group_default_credits if shutoff_credits is not UNSET: field_dict["shutoffCredits"] = shutoff_credits if user_default_credits is not UNSET: @@ -72,6 +84,15 @@ def _parse_downgrade_credits(data: object) -> float | None | Unset: downgrade_credits = _parse_downgrade_credits(d.pop("downgradeCredits", UNSET)) + def _parse_entity_group_default_credits(data: object) -> float | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(float | None | Unset, data) + + entity_group_default_credits = _parse_entity_group_default_credits(d.pop("entityGroupDefaultCredits", UNSET)) + def _parse_shutoff_credits(data: object) -> float | None | Unset: if data is None: return data @@ -92,6 +113,7 @@ def _parse_user_default_credits(data: object) -> float | None | Unset: ai_credit_controls_update_body = cls( downgrade_credits=downgrade_credits, + entity_group_default_credits=entity_group_default_credits, shutoff_credits=shutoff_credits, user_default_credits=user_default_credits, ) diff --git a/omni_python_sdk/models/ai_entity_group_credit_limit_entry.py b/omni_python_sdk/models/ai_entity_group_credit_limit_entry.py new file mode 100644 index 0000000..88097f7 --- /dev/null +++ b/omni_python_sdk/models/ai_entity_group_credit_limit_entry.py @@ -0,0 +1,76 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define + +from ..types import UNSET, Unset + +T = TypeVar("T", bound="AiEntityGroupCreditLimitEntry") + + +@_attrs_define +class AiEntityGroupCreditLimitEntry: + """ + Attributes: + entity (str): The embed entity's identifier (the SSO `entity` value). Example: acme-corp. + credit_limit (float | None | Unset): The entity group's individual AI credit limit for the billing period, or + `null` for unlimited. Either way this overrides the org default. Mutually exclusive with `useDefaultLimit`. + Example: 50. + use_default_limit (bool | Unset): Removes the entity group's individual limit so it follows the org default. + Mutually exclusive with `creditLimit`. + """ + + entity: str + credit_limit: float | None | Unset = UNSET + use_default_limit: bool | Unset = UNSET + + def to_dict(self) -> dict[str, Any]: + entity = self.entity + + credit_limit: float | None | Unset + if isinstance(self.credit_limit, Unset): + credit_limit = UNSET + else: + credit_limit = self.credit_limit + + use_default_limit = self.use_default_limit + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "entity": entity, + } + ) + if credit_limit is not UNSET: + field_dict["creditLimit"] = credit_limit + if use_default_limit is not UNSET: + field_dict["useDefaultLimit"] = use_default_limit + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + entity = d.pop("entity") + + def _parse_credit_limit(data: object) -> float | None | Unset: + if data is None: + return data + if isinstance(data, Unset): + return data + return cast(float | None | Unset, data) + + credit_limit = _parse_credit_limit(d.pop("creditLimit", UNSET)) + + use_default_limit = d.pop("useDefaultLimit", UNSET) + + ai_entity_group_credit_limit_entry = cls( + entity=entity, + credit_limit=credit_limit, + use_default_limit=use_default_limit, + ) + + return ai_entity_group_credit_limit_entry diff --git a/omni_python_sdk/models/ai_entity_group_credit_limits_response.py b/omni_python_sdk/models/ai_entity_group_credit_limits_response.py new file mode 100644 index 0000000..c3a2ecd --- /dev/null +++ b/omni_python_sdk/models/ai_entity_group_credit_limits_response.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.ai_entity_group_credit_limits_response_entity_groups_item import ( + AiEntityGroupCreditLimitsResponseEntityGroupsItem, + ) + + +T = TypeVar("T", bound="AiEntityGroupCreditLimitsResponse") + + +@_attrs_define +class AiEntityGroupCreditLimitsResponse: + """ + Attributes: + entity_groups (list[AiEntityGroupCreditLimitsResponseEntityGroupsItem]): + """ + + entity_groups: list[AiEntityGroupCreditLimitsResponseEntityGroupsItem] + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + entity_groups = [] + for entity_groups_item_data in self.entity_groups: + entity_groups_item = entity_groups_item_data.to_dict() + entity_groups.append(entity_groups_item) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "entityGroups": entity_groups, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_entity_group_credit_limits_response_entity_groups_item import ( + AiEntityGroupCreditLimitsResponseEntityGroupsItem, + ) + + d = dict(src_dict) + entity_groups = [] + _entity_groups = d.pop("entityGroups") + for entity_groups_item_data in _entity_groups: + entity_groups_item = AiEntityGroupCreditLimitsResponseEntityGroupsItem.from_dict(entity_groups_item_data) + + entity_groups.append(entity_groups_item) + + ai_entity_group_credit_limits_response = cls( + entity_groups=entity_groups, + ) + + ai_entity_group_credit_limits_response.additional_properties = d + return ai_entity_group_credit_limits_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_entity_group_credit_limits_response_entity_groups_item.py b/omni_python_sdk/models/ai_entity_group_credit_limits_response_entity_groups_item.py new file mode 100644 index 0000000..36c890c --- /dev/null +++ b/omni_python_sdk/models/ai_entity_group_credit_limits_response_entity_groups_item.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="AiEntityGroupCreditLimitsResponseEntityGroupsItem") + + +@_attrs_define +class AiEntityGroupCreditLimitsResponseEntityGroupsItem: + """ + Attributes: + credit_limit (float | None): The entity group's effective AI credit limit, or `null` for unlimited. Example: 50. + entity (str): The embed entity's identifier (the SSO `entity` value). Example: acme-corp. + uses_default_limit (bool): True when the entity group has no individual limit and follows the org default. + """ + + credit_limit: float | None + entity: str + uses_default_limit: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + credit_limit: float | None + credit_limit = self.credit_limit + + entity = self.entity + + uses_default_limit = self.uses_default_limit + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "creditLimit": credit_limit, + "entity": entity, + "usesDefaultLimit": uses_default_limit, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_credit_limit(data: object) -> float | None: + if data is None: + return data + return cast(float | None, data) + + credit_limit = _parse_credit_limit(d.pop("creditLimit")) + + entity = d.pop("entity") + + uses_default_limit = d.pop("usesDefaultLimit") + + ai_entity_group_credit_limits_response_entity_groups_item = cls( + credit_limit=credit_limit, + entity=entity, + uses_default_limit=uses_default_limit, + ) + + ai_entity_group_credit_limits_response_entity_groups_item.additional_properties = d + return ai_entity_group_credit_limits_response_entity_groups_item + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/ai_entity_group_credit_limits_update_body.py b/omni_python_sdk/models/ai_entity_group_credit_limits_update_body.py new file mode 100644 index 0000000..d806d17 --- /dev/null +++ b/omni_python_sdk/models/ai_entity_group_credit_limits_update_body.py @@ -0,0 +1,57 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define + +if TYPE_CHECKING: + from ..models.ai_entity_group_credit_limit_entry import AiEntityGroupCreditLimitEntry + + +T = TypeVar("T", bound="AiEntityGroupCreditLimitsUpdateBody") + + +@_attrs_define +class AiEntityGroupCreditLimitsUpdateBody: + """ + Attributes: + entity_groups (list[AiEntityGroupCreditLimitEntry]): Entity groups to update, at most 1000 per request. Each + entry has an `entity` plus exactly one of `creditLimit` (number or `null`) or `useDefaultLimit: true`. + """ + + entity_groups: list[AiEntityGroupCreditLimitEntry] + + def to_dict(self) -> dict[str, Any]: + entity_groups = [] + for entity_groups_item_data in self.entity_groups: + entity_groups_item = entity_groups_item_data.to_dict() + entity_groups.append(entity_groups_item) + + field_dict: dict[str, Any] = {} + + field_dict.update( + { + "entityGroups": entity_groups, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.ai_entity_group_credit_limit_entry import AiEntityGroupCreditLimitEntry + + d = dict(src_dict) + entity_groups = [] + _entity_groups = d.pop("entityGroups") + for entity_groups_item_data in _entity_groups: + entity_groups_item = AiEntityGroupCreditLimitEntry.from_dict(entity_groups_item_data) + + entity_groups.append(entity_groups_item) + + ai_entity_group_credit_limits_update_body = cls( + entity_groups=entity_groups, + ) + + return ai_entity_group_credit_limits_update_body diff --git a/omni_python_sdk/models/ai_job_submit_body.py b/omni_python_sdk/models/ai_job_submit_body.py index ab6795c..edbfad5 100644 --- a/omni_python_sdk/models/ai_job_submit_body.py +++ b/omni_python_sdk/models/ai_job_submit_body.py @@ -10,6 +10,7 @@ from ..types import UNSET, Unset if TYPE_CHECKING: + from ..models.agentic_job_attachment import AgenticJobAttachment from ..models.ai_job_submit_body_webhook_metadata import AiJobSubmitBodyWebhookMetadata @@ -25,8 +26,13 @@ class AiJobSubmitBody: prompt (str): The natural language prompt for the AI to process. The AI will analyze your question, generate appropriate queries, execute them, and return a summarized answer. Example: What are the top 5 products by revenue this quarter?. + attachments (list[AgenticJobAttachment] | Unset): Optional image or PDF attachments (e.g. a screenshot or export + of a legacy BI dashboard being migrated) giving the AI additional visual context alongside the prompt. Up to 5 + files, sharing a combined 50000-token budget with the rest of the prompt. branch_id (UUID | Unset): Optional branch ID for the model. Must be a branch of the shared model specified by - modelId. Use this to query against in-progress model changes. Example: 550e8400-e29b-41d4-a716-446655440000. + modelId. Queries run against the branch model, and if the AI makes model changes (organizations with agentic + modeling enabled), they are written to this branch instead of a newly created one. If omitted and the AI makes + model changes, a new branch is created automatically. Example: 550e8400-e29b-41d4-a716-446655440000. conversation_id (UUID | Unset): Conversation ID to continue an existing conversation thread. The AI will have access to the context from previous jobs in the same conversation. If omitted, a new conversation is created. Only one active job can exist per conversation. Example: 660e8400-e29b-41d4-a716-446655440001. @@ -51,6 +57,7 @@ class AiJobSubmitBody: model_id: UUID prompt: str + attachments: list[AgenticJobAttachment] | Unset = UNSET branch_id: UUID | Unset = UNSET conversation_id: UUID | Unset = UNSET progress_webhook_enabled: bool | Unset = False @@ -65,6 +72,13 @@ def to_dict(self) -> dict[str, Any]: prompt = self.prompt + attachments: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.attachments, Unset): + attachments = [] + for attachments_item_data in self.attachments: + attachments_item = attachments_item_data.to_dict() + attachments.append(attachments_item) + branch_id: str | Unset = UNSET if not isinstance(self.branch_id, Unset): branch_id = str(self.branch_id) @@ -93,6 +107,8 @@ def to_dict(self) -> dict[str, Any]: "prompt": prompt, } ) + if attachments is not UNSET: + field_dict["attachments"] = attachments if branch_id is not UNSET: field_dict["branchId"] = branch_id if conversation_id is not UNSET: @@ -112,6 +128,7 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.agentic_job_attachment import AgenticJobAttachment from ..models.ai_job_submit_body_webhook_metadata import AiJobSubmitBodyWebhookMetadata d = dict(src_dict) @@ -119,6 +136,15 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: prompt = d.pop("prompt") + _attachments = d.pop("attachments", UNSET) + attachments: list[AgenticJobAttachment] | Unset = UNSET + if _attachments is not UNSET: + attachments = [] + for attachments_item_data in _attachments: + attachments_item = AgenticJobAttachment.from_dict(attachments_item_data) + + attachments.append(attachments_item) + _branch_id = d.pop("branchId", UNSET) branch_id: UUID | Unset if isinstance(_branch_id, Unset): @@ -151,6 +177,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: ai_job_submit_body = cls( model_id=model_id, prompt=prompt, + attachments=attachments, branch_id=branch_id, conversation_id=conversation_id, progress_webhook_enabled=progress_webhook_enabled, diff --git a/omni_python_sdk/models/create_model_schema_base.py b/omni_python_sdk/models/create_model_schema_base.py index cb3a67a..3194a1f 100644 --- a/omni_python_sdk/models/create_model_schema_base.py +++ b/omni_python_sdk/models/create_model_schema_base.py @@ -22,6 +22,10 @@ CreateModelSchemaBaseModelKindType3, check_create_model_schema_base_model_kind_type_3, ) +from ..models.create_model_schema_base_model_kind_type_4 import ( + CreateModelSchemaBaseModelKindType4, + check_create_model_schema_base_model_kind_type_4, +) from ..types import UNSET, Unset if TYPE_CHECKING: @@ -40,8 +44,8 @@ class CreateModelSchemaBase: allow_as_workbook_base (bool | Unset): Allow this model as a workbook base base_model_id (str | Unset): Base model ID for extension or branch models model_kind (CreateModelSchemaBaseModelKindType0 | CreateModelSchemaBaseModelKindType1 | - CreateModelSchemaBaseModelKindType2 | CreateModelSchemaBaseModelKindType3 | Unset): Kind of model to create - Default: 'SCHEMA'. + CreateModelSchemaBaseModelKindType2 | CreateModelSchemaBaseModelKindType3 | CreateModelSchemaBaseModelKindType4 + | Unset): Kind of model to create Default: 'SCHEMA'. model_name (str | Unset): Name for the model uses_isolated_branches (bool | Unset): For SHARED_EXTENSION models, controls if branches are shown on extension model page instead of parent shared model @@ -56,6 +60,7 @@ class CreateModelSchemaBase: | CreateModelSchemaBaseModelKindType1 | CreateModelSchemaBaseModelKindType2 | CreateModelSchemaBaseModelKindType3 + | CreateModelSchemaBaseModelKindType4 | Unset ) = "SCHEMA" model_name: str | Unset = UNSET @@ -85,6 +90,8 @@ def to_dict(self) -> dict[str, Any]: model_kind = self.model_kind elif isinstance(self.model_kind, str): model_kind = self.model_kind + elif isinstance(self.model_kind, str): + model_kind = self.model_kind else: model_kind = self.model_kind @@ -141,6 +148,7 @@ def _parse_model_kind( | CreateModelSchemaBaseModelKindType1 | CreateModelSchemaBaseModelKindType2 | CreateModelSchemaBaseModelKindType3 + | CreateModelSchemaBaseModelKindType4 | Unset ): if isinstance(data, Unset): @@ -169,11 +177,19 @@ def _parse_model_kind( return model_kind_type_2 except (TypeError, ValueError, AttributeError, KeyError): pass + try: + if not isinstance(data, str): + raise TypeError() + model_kind_type_3 = check_create_model_schema_base_model_kind_type_3(data) + + return model_kind_type_3 + except (TypeError, ValueError, AttributeError, KeyError): + pass if not isinstance(data, str): raise TypeError() - model_kind_type_3 = check_create_model_schema_base_model_kind_type_3(data) + model_kind_type_4 = check_create_model_schema_base_model_kind_type_4(data) - return model_kind_type_3 + return model_kind_type_4 model_kind = _parse_model_kind(d.pop("modelKind", UNSET)) diff --git a/omni_python_sdk/models/create_model_schema_base_model_kind_type_4.py b/omni_python_sdk/models/create_model_schema_base_model_kind_type_4.py new file mode 100644 index 0000000..d453f60 --- /dev/null +++ b/omni_python_sdk/models/create_model_schema_base_model_kind_type_4.py @@ -0,0 +1,15 @@ +from typing import Literal + +CreateModelSchemaBaseModelKindType4 = Literal["QUERY"] + +CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_4_VALUES: set[CreateModelSchemaBaseModelKindType4] = { + "QUERY", +} + + +def check_create_model_schema_base_model_kind_type_4(value: str) -> CreateModelSchemaBaseModelKindType4: + if value in CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_4_VALUES: + return value + raise TypeError( + f"Unexpected value {value!r}. Expected one of {CREATE_MODEL_SCHEMA_BASE_MODEL_KIND_TYPE_4_VALUES!r}" + ) diff --git a/omni_python_sdk/models/document_abilities.py b/omni_python_sdk/models/document_abilities.py new file mode 100644 index 0000000..24f1ca6 --- /dev/null +++ b/omni_python_sdk/models/document_abilities.py @@ -0,0 +1,150 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="DocumentAbilities") + + +@_attrs_define +class DocumentAbilities: + """Document-level ability values, as stored on the document + + Attributes: + can_analyze (bool): Allow exploring from this document + can_download (bool): Allow downloading + can_drill (bool): Allow drill-down + can_duplicate (bool): Allow duplicating + can_request_access (bool): Allow requesting access + can_save_spreadsheets (bool): Allow creating spreadsheets + can_schedule (bool): Allow scheduling + can_upload (bool): Allow uploads + can_use_dashboard_ai (bool): Allow using dashboard AI + can_use_timezone_override (bool): Allow timezone override + can_view_workbook (bool): Allow viewing workbook + require_pull_request_to_publish (bool): Require pull request to publish changes + """ + + can_analyze: bool + can_download: bool + can_drill: bool + can_duplicate: bool + can_request_access: bool + can_save_spreadsheets: bool + can_schedule: bool + can_upload: bool + can_use_dashboard_ai: bool + can_use_timezone_override: bool + can_view_workbook: bool + require_pull_request_to_publish: bool + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + can_analyze = self.can_analyze + + can_download = self.can_download + + can_drill = self.can_drill + + can_duplicate = self.can_duplicate + + can_request_access = self.can_request_access + + can_save_spreadsheets = self.can_save_spreadsheets + + can_schedule = self.can_schedule + + can_upload = self.can_upload + + can_use_dashboard_ai = self.can_use_dashboard_ai + + can_use_timezone_override = self.can_use_timezone_override + + can_view_workbook = self.can_view_workbook + + require_pull_request_to_publish = self.require_pull_request_to_publish + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "canAnalyze": can_analyze, + "canDownload": can_download, + "canDrill": can_drill, + "canDuplicate": can_duplicate, + "canRequestAccess": can_request_access, + "canSaveSpreadsheets": can_save_spreadsheets, + "canSchedule": can_schedule, + "canUpload": can_upload, + "canUseDashboardAi": can_use_dashboard_ai, + "canUseTimezoneOverride": can_use_timezone_override, + "canViewWorkbook": can_view_workbook, + "requirePullRequestToPublish": require_pull_request_to_publish, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + can_analyze = d.pop("canAnalyze") + + can_download = d.pop("canDownload") + + can_drill = d.pop("canDrill") + + can_duplicate = d.pop("canDuplicate") + + can_request_access = d.pop("canRequestAccess") + + can_save_spreadsheets = d.pop("canSaveSpreadsheets") + + can_schedule = d.pop("canSchedule") + + can_upload = d.pop("canUpload") + + can_use_dashboard_ai = d.pop("canUseDashboardAi") + + can_use_timezone_override = d.pop("canUseTimezoneOverride") + + can_view_workbook = d.pop("canViewWorkbook") + + require_pull_request_to_publish = d.pop("requirePullRequestToPublish") + + document_abilities = cls( + can_analyze=can_analyze, + can_download=can_download, + can_drill=can_drill, + can_duplicate=can_duplicate, + can_request_access=can_request_access, + can_save_spreadsheets=can_save_spreadsheets, + can_schedule=can_schedule, + can_upload=can_upload, + can_use_dashboard_ai=can_use_dashboard_ai, + can_use_timezone_override=can_use_timezone_override, + can_view_workbook=can_view_workbook, + require_pull_request_to_publish=require_pull_request_to_publish, + ) + + document_abilities.additional_properties = d + return document_abilities + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/documents_get_permissions_response.py b/omni_python_sdk/models/documents_get_permissions_response.py index dc7e092..3e9e9ae 100644 --- a/omni_python_sdk/models/documents_get_permissions_response.py +++ b/omni_python_sdk/models/documents_get_permissions_response.py @@ -1,13 +1,17 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Any, TypeVar +from typing import TYPE_CHECKING, Any, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field from ..types import UNSET, Unset +if TYPE_CHECKING: + from ..models.document_abilities import DocumentAbilities + + T = TypeVar("T", bound="DocumentsGetPermissionsResponse") @@ -15,18 +19,26 @@ class DocumentsGetPermissionsResponse: """ Attributes: - permits (Any | Unset): User permits for the document + abilities (DocumentAbilities): Document-level ability values, as stored on the document + permits (Any | Unset): User permits for the document. Present only when userId is provided. """ + abilities: DocumentAbilities permits: Any | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: + abilities = self.abilities.to_dict() + permits = self.permits field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update({}) + field_dict.update( + { + "abilities": abilities, + } + ) if permits is not UNSET: field_dict["permits"] = permits @@ -34,10 +46,15 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.document_abilities import DocumentAbilities + d = dict(src_dict) + abilities = DocumentAbilities.from_dict(d.pop("abilities")) + permits = d.pop("permits", UNSET) documents_get_permissions_response = cls( + abilities=abilities, permits=permits, ) diff --git a/omni_python_sdk/models/documents_update_permission_settings_body.py b/omni_python_sdk/models/documents_update_permission_settings_body.py index ac65551..1aefcfc 100644 --- a/omni_python_sdk/models/documents_update_permission_settings_body.py +++ b/omni_python_sdk/models/documents_update_permission_settings_body.py @@ -19,8 +19,12 @@ class DocumentsUpdatePermissionSettingsBody: """ Attributes: + can_analyze (bool | Unset): Allow exploring from this document can_download (bool | Unset): Allow downloading can_drill (bool | Unset): Allow drill-down + can_duplicate (bool | Unset): Allow duplicating + can_request_access (bool | Unset): Allow requesting access + can_save_spreadsheets (bool | Unset): Allow creating spreadsheets can_schedule (bool | Unset): Allow scheduling can_upload (bool | Unset): Allow uploads can_use_dashboard_ai (bool | Unset): Allow using dashboard AI @@ -32,8 +36,12 @@ class DocumentsUpdatePermissionSettingsBody: require_pull_request_to_publish (bool | Unset): Require pull request to publish changes """ + can_analyze: bool | Unset = UNSET can_download: bool | Unset = UNSET can_drill: bool | Unset = UNSET + can_duplicate: bool | Unset = UNSET + can_request_access: bool | Unset = UNSET + can_save_spreadsheets: bool | Unset = UNSET can_schedule: bool | Unset = UNSET can_upload: bool | Unset = UNSET can_use_dashboard_ai: bool | Unset = UNSET @@ -45,10 +53,18 @@ class DocumentsUpdatePermissionSettingsBody: additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: + can_analyze = self.can_analyze + can_download = self.can_download can_drill = self.can_drill + can_duplicate = self.can_duplicate + + can_request_access = self.can_request_access + + can_save_spreadsheets = self.can_save_spreadsheets + can_schedule = self.can_schedule can_upload = self.can_upload @@ -70,10 +86,18 @@ def to_dict(self) -> dict[str, Any]: field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({}) + if can_analyze is not UNSET: + field_dict["canAnalyze"] = can_analyze if can_download is not UNSET: field_dict["canDownload"] = can_download if can_drill is not UNSET: field_dict["canDrill"] = can_drill + if can_duplicate is not UNSET: + field_dict["canDuplicate"] = can_duplicate + if can_request_access is not UNSET: + field_dict["canRequestAccess"] = can_request_access + if can_save_spreadsheets is not UNSET: + field_dict["canSaveSpreadsheets"] = can_save_spreadsheets if can_schedule is not UNSET: field_dict["canSchedule"] = can_schedule if can_upload is not UNSET: @@ -96,10 +120,18 @@ def to_dict(self) -> dict[str, Any]: @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) + can_analyze = d.pop("canAnalyze", UNSET) + can_download = d.pop("canDownload", UNSET) can_drill = d.pop("canDrill", UNSET) + can_duplicate = d.pop("canDuplicate", UNSET) + + can_request_access = d.pop("canRequestAccess", UNSET) + + can_save_spreadsheets = d.pop("canSaveSpreadsheets", UNSET) + can_schedule = d.pop("canSchedule", UNSET) can_upload = d.pop("canUpload", UNSET) @@ -122,8 +154,12 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: require_pull_request_to_publish = d.pop("requirePullRequestToPublish", UNSET) documents_update_permission_settings_body = cls( + can_analyze=can_analyze, can_download=can_download, can_drill=can_drill, + can_duplicate=can_duplicate, + can_request_access=can_request_access, + can_save_spreadsheets=can_save_spreadsheets, can_schedule=can_schedule, can_upload=can_upload, can_use_dashboard_ai=can_use_dashboard_ai, diff --git a/omni_python_sdk/models/documents_v2_create_draft_body.py b/omni_python_sdk/models/documents_v2_create_draft_body.py index a4f3b56..e21750e 100644 --- a/omni_python_sdk/models/documents_v2_create_draft_body.py +++ b/omni_python_sdk/models/documents_v2_create_draft_body.py @@ -36,6 +36,9 @@ class DocumentsV2CreateDraftBody: model_id (UUID | Unset): The document's base model. Immutable and accepted only so a GET response round-trips through PATCH: a value matching the current model is a no-op, and a differing value is rejected — it cannot re- base the document. Omit it to leave the model untouched. + workbook_model_id (UUID | Unset): The server-assigned workbook-layer model. Read-only and accepted only so a GET + response round-trips through PATCH: a value from a GET of the draft or of the published document it targets is a + no-op, and any other value is rejected. Omit it otherwise. branch_id (UUID | Unset): Branch the draft is created on. Omit for a draft on the main (unpublished) workspace. """ @@ -47,6 +50,7 @@ class DocumentsV2CreateDraftBody: settings: SettingsPatchExternal | Unset = UNSET summary: str | Unset = UNSET model_id: UUID | Unset = UNSET + workbook_model_id: UUID | Unset = UNSET branch_id: UUID | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) @@ -84,6 +88,10 @@ def to_dict(self) -> dict[str, Any]: if not isinstance(self.model_id, Unset): model_id = str(self.model_id) + workbook_model_id: str | Unset = UNSET + if not isinstance(self.workbook_model_id, Unset): + workbook_model_id = str(self.workbook_model_id) + branch_id: str | Unset = UNSET if not isinstance(self.branch_id, Unset): branch_id = str(self.branch_id) @@ -107,6 +115,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["summary"] = summary if model_id is not UNSET: field_dict["modelId"] = model_id + if workbook_model_id is not UNSET: + field_dict["workbookModelId"] = workbook_model_id if branch_id is not UNSET: field_dict["branchId"] = branch_id @@ -170,6 +180,13 @@ def _parse_description(data: object) -> None | str | Unset: else: model_id = UUID(_model_id) + _workbook_model_id = d.pop("workbookModelId", UNSET) + workbook_model_id: UUID | Unset + if isinstance(_workbook_model_id, Unset): + workbook_model_id = UNSET + else: + workbook_model_id = UUID(_workbook_model_id) + _branch_id = d.pop("branchId", UNSET) branch_id: UUID | Unset if isinstance(_branch_id, Unset): @@ -186,6 +203,7 @@ def _parse_description(data: object) -> None | str | Unset: settings=settings, summary=summary, model_id=model_id, + workbook_model_id=workbook_model_id, branch_id=branch_id, ) diff --git a/omni_python_sdk/models/documents_v2_patch_draft_body.py b/omni_python_sdk/models/documents_v2_patch_draft_body.py index 15b31ac..be2623c 100644 --- a/omni_python_sdk/models/documents_v2_patch_draft_body.py +++ b/omni_python_sdk/models/documents_v2_patch_draft_body.py @@ -35,6 +35,9 @@ class DocumentsV2PatchDraftBody: model_id (UUID | Unset): The document's base model. Immutable and accepted only so a GET response round-trips through PATCH: a value matching the current model is a no-op, and a differing value is rejected — it cannot re- base the document. Omit it to leave the model untouched. + workbook_model_id (UUID | Unset): The server-assigned workbook-layer model. Read-only and accepted only so a GET + response round-trips through PATCH: a value from a GET of the draft or of the published document it targets is a + no-op, and any other value is rejected. Omit it otherwise. """ containers: list[ContainersItem] | Unset = UNSET @@ -45,6 +48,7 @@ class DocumentsV2PatchDraftBody: settings: SettingsPatchExternal | Unset = UNSET summary: str | Unset = UNSET model_id: UUID | Unset = UNSET + workbook_model_id: UUID | Unset = UNSET def to_dict(self) -> dict[str, Any]: containers: list[dict[str, Any]] | Unset = UNSET @@ -80,6 +84,10 @@ def to_dict(self) -> dict[str, Any]: if not isinstance(self.model_id, Unset): model_id = str(self.model_id) + workbook_model_id: str | Unset = UNSET + if not isinstance(self.workbook_model_id, Unset): + workbook_model_id = str(self.workbook_model_id) + field_dict: dict[str, Any] = {} field_dict.update({}) @@ -99,6 +107,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["summary"] = summary if model_id is not UNSET: field_dict["modelId"] = model_id + if workbook_model_id is not UNSET: + field_dict["workbookModelId"] = workbook_model_id return field_dict @@ -160,6 +170,13 @@ def _parse_description(data: object) -> None | str | Unset: else: model_id = UUID(_model_id) + _workbook_model_id = d.pop("workbookModelId", UNSET) + workbook_model_id: UUID | Unset + if isinstance(_workbook_model_id, Unset): + workbook_model_id = UNSET + else: + workbook_model_id = UUID(_workbook_model_id) + documents_v2_patch_draft_body = cls( containers=containers, controls=controls, @@ -169,6 +186,7 @@ def _parse_description(data: object) -> None | str | Unset: settings=settings, summary=summary, model_id=model_id, + workbook_model_id=workbook_model_id, ) return documents_v2_patch_draft_body diff --git a/omni_python_sdk/models/documents_v2_read_response.py b/omni_python_sdk/models/documents_v2_read_response.py index a06f30b..890b698 100644 --- a/omni_python_sdk/models/documents_v2_read_response.py +++ b/omni_python_sdk/models/documents_v2_read_response.py @@ -28,6 +28,8 @@ class DocumentsV2ReadResponse: so a GET round-trips through PATCH; supplying a different value on PATCH is rejected. name (str): Document name. query_presentations (QueryPresentationsReadExternal): (Not statically modeled; use plain dicts.) + workbook_model_id (UUID): Server-assigned WORKBOOK-layer model layered on `modelId`. Read-only — echoed here so + a GET round-trips through PATCH; each draft has its own, so a draft read returns the draft workbook’s model. containers (list[ContainersItem] | Unset): Container layout array (grid / stack / page / reference containers, recursively nested). The server validates the full structure on apply. (Not statically modeled; use plain dicts.) @@ -39,6 +41,7 @@ class DocumentsV2ReadResponse: model_id: UUID name: str query_presentations: QueryPresentationsReadExternal + workbook_model_id: UUID containers: list[ContainersItem] | Unset = UNSET controls: ControlsReadExternal | Unset = UNSET settings: SettingsReadExternal | Unset = UNSET @@ -54,6 +57,8 @@ def to_dict(self) -> dict[str, Any]: query_presentations = self.query_presentations.to_dict() + workbook_model_id = str(self.workbook_model_id) + containers: list[dict[str, Any]] | Unset = UNSET if not isinstance(self.containers, Unset): containers = [] @@ -77,6 +82,7 @@ def to_dict(self) -> dict[str, Any]: "modelId": model_id, "name": name, "queryPresentations": query_presentations, + "workbookModelId": workbook_model_id, } ) if containers is not UNSET: @@ -110,6 +116,8 @@ def _parse_description(data: object) -> None | str: query_presentations = QueryPresentationsReadExternal.from_dict(d.pop("queryPresentations")) + workbook_model_id = UUID(d.pop("workbookModelId")) + _containers = d.pop("containers", UNSET) containers: list[ContainersItem] | Unset = UNSET if _containers is not UNSET: @@ -138,6 +146,7 @@ def _parse_description(data: object) -> None | str: model_id=model_id, name=name, query_presentations=query_presentations, + workbook_model_id=workbook_model_id, containers=containers, controls=controls, settings=settings, diff --git a/omni_python_sdk/models/eval_run_detail.py b/omni_python_sdk/models/eval_run_detail.py index 539ff10..7cc1abd 100644 --- a/omni_python_sdk/models/eval_run_detail.py +++ b/omni_python_sdk/models/eval_run_detail.py @@ -31,8 +31,10 @@ class EvalRunDetail: is_archived (bool): Whether the run has been archived. model_id (UUID): The shared model this run was executed against. Example: 880e8400-e29b-41d4-a716-446655440003. prompt_set_id (UUID): The prompt set this run was created from. Example: 550e8400-e29b-41d4-a716-446655440000. - results (list[EvalRunResult]): Per-prompt results for this run, ordered by their creation order in the prompt - set. + repeat_count (int): How many times each prompt in the set was executed. Results carry a `repeat_index` when this + is greater than 1. Example: 1. + results (list[EvalRunResult]): Per-execution results for this run (one per prompt, times the repeat count). No + guaranteed order — group executions by `eval_prompt_id` and order by `repeat_index`. run_number (int): Sequential, per-prompt-set run number. Example: 3. status (EvalRunDetailStatus): Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly once. Example: RUNNING. @@ -47,6 +49,7 @@ class EvalRunDetail: is_archived: bool model_id: UUID prompt_set_id: UUID + repeat_count: int results: list[EvalRunResult] run_number: int status: EvalRunDetailStatus @@ -79,6 +82,8 @@ def to_dict(self) -> dict[str, Any]: prompt_set_id = str(self.prompt_set_id) + repeat_count = self.repeat_count + results = [] for results_item_data in self.results: results_item = results_item_data.to_dict() @@ -101,6 +106,7 @@ def to_dict(self) -> dict[str, Any]: "is_archived": is_archived, "model_id": model_id, "prompt_set_id": prompt_set_id, + "repeat_count": repeat_count, "results": results, "run_number": run_number, "status": status, @@ -166,6 +172,8 @@ def _parse_description(data: object) -> None | str: prompt_set_id = UUID(d.pop("prompt_set_id")) + repeat_count = d.pop("repeat_count") + results = [] _results = d.pop("results") for results_item_data in _results: @@ -187,6 +195,7 @@ def _parse_description(data: object) -> None | str: is_archived=is_archived, model_id=model_id, prompt_set_id=prompt_set_id, + repeat_count=repeat_count, results=results, run_number=run_number, status=status, diff --git a/omni_python_sdk/models/eval_run_list_item.py b/omni_python_sdk/models/eval_run_list_item.py index 5f72990..22282b3 100644 --- a/omni_python_sdk/models/eval_run_list_item.py +++ b/omni_python_sdk/models/eval_run_list_item.py @@ -30,6 +30,7 @@ class EvalRunListItem: is_archived (bool): Whether the run has been archived. model_id (UUID): The shared model this run was executed against. Example: 880e8400-e29b-41d4-a716-446655440003. prompt_set_id (UUID): The prompt set this run was created from. Example: 550e8400-e29b-41d4-a716-446655440000. + repeat_count (int): How many times each prompt in the set was executed. Example: 1. run_number (int): Sequential, per-prompt-set run number. Example: 3. stats (EvalRunStats): status (EvalRunListItemStatus): Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly @@ -45,6 +46,7 @@ class EvalRunListItem: is_archived: bool model_id: UUID prompt_set_id: UUID + repeat_count: int run_number: int stats: EvalRunStats status: EvalRunListItemStatus @@ -77,6 +79,8 @@ def to_dict(self) -> dict[str, Any]: prompt_set_id = str(self.prompt_set_id) + repeat_count = self.repeat_count + run_number = self.run_number stats = self.stats.to_dict() @@ -96,6 +100,7 @@ def to_dict(self) -> dict[str, Any]: "is_archived": is_archived, "model_id": model_id, "prompt_set_id": prompt_set_id, + "repeat_count": repeat_count, "run_number": run_number, "stats": stats, "status": status, @@ -161,6 +166,8 @@ def _parse_description(data: object) -> None | str: prompt_set_id = UUID(d.pop("prompt_set_id")) + repeat_count = d.pop("repeat_count") + run_number = d.pop("run_number") stats = EvalRunStats.from_dict(d.pop("stats")) @@ -177,6 +184,7 @@ def _parse_description(data: object) -> None | str: is_archived=is_archived, model_id=model_id, prompt_set_id=prompt_set_id, + repeat_count=repeat_count, run_number=run_number, stats=stats, status=status, diff --git a/omni_python_sdk/models/eval_run_result.py b/omni_python_sdk/models/eval_run_result.py index 6c319d9..f186faf 100644 --- a/omni_python_sdk/models/eval_run_result.py +++ b/omni_python_sdk/models/eval_run_result.py @@ -25,6 +25,9 @@ class EvalRunResult: latency). Example: 4121. cost (float | None): Total LLM cost (USD) for this prompt, if available. Example: 0.0021. error_reason (None | str): Failure reason string for prompts whose underlying job failed. + eval_prompt_id (None | UUID): Snapshot of the prompt id this result was executed for — repeated executions of + the same prompt share it, and it survives later prompt deletion. Null on runs created before repeats existed. + Example: bb0e8400-e29b-41d4-a716-446655440007. expectation (None | str): The prompt's expectation as of run creation (snapshotted, so later prompt edits don't change past runs), or null when none was set. The analysis judge scores the analysis against it. Example: The top product by revenue should be Aniseed Syrup.. @@ -35,6 +38,8 @@ class EvalRunResult: query_timing_ms (int | None): Total wall-clock time (milliseconds) the underlying job spent running warehouse queries — a proxy for query execution time. Null for runs executed before this metric was recorded. Example: 1800. + repeat_index (int | None): 0-based repeat number of this execution within the run (see the run's + `repeat_count`). Null on runs created before repeats existed. score (float | None): Numeric judge score for this prompt result, if scoring ran. Example: 0.9. scoring_cost (float | None): Total LLM cost (USD) for scoring this prompt result. Example: 0.0004. timing_ms (int | None): Total `/generate` wall-time in milliseconds — LLM processing plus inner-loop tool @@ -49,11 +54,13 @@ class EvalRunResult: ai_timing_ms: int | None cost: float | None error_reason: None | str + eval_prompt_id: None | UUID expectation: None | str id: UUID prompt: str query_count: int | None query_timing_ms: int | None + repeat_index: int | None score: float | None scoring_cost: float | None timing_ms: int | None @@ -72,6 +79,12 @@ def to_dict(self) -> dict[str, Any]: error_reason: None | str error_reason = self.error_reason + eval_prompt_id: None | str + if isinstance(self.eval_prompt_id, UUID): + eval_prompt_id = str(self.eval_prompt_id) + else: + eval_prompt_id = self.eval_prompt_id + expectation: None | str expectation = self.expectation @@ -85,6 +98,9 @@ def to_dict(self) -> dict[str, Any]: query_timing_ms: int | None query_timing_ms = self.query_timing_ms + repeat_index: int | None + repeat_index = self.repeat_index + score: float | None score = self.score @@ -105,11 +121,13 @@ def to_dict(self) -> dict[str, Any]: "ai_timing_ms": ai_timing_ms, "cost": cost, "error_reason": error_reason, + "eval_prompt_id": eval_prompt_id, "expectation": expectation, "id": id, "prompt": prompt, "query_count": query_count, "query_timing_ms": query_timing_ms, + "repeat_index": repeat_index, "score": score, "scoring_cost": scoring_cost, "timing_ms": timing_ms, @@ -147,6 +165,21 @@ def _parse_error_reason(data: object) -> None | str: error_reason = _parse_error_reason(d.pop("error_reason")) + def _parse_eval_prompt_id(data: object) -> None | UUID: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + eval_prompt_id_type_0 = UUID(data) + + return eval_prompt_id_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UUID, data) + + eval_prompt_id = _parse_eval_prompt_id(d.pop("eval_prompt_id")) + def _parse_expectation(data: object) -> None | str: if data is None: return data @@ -172,6 +205,13 @@ def _parse_query_timing_ms(data: object) -> int | None: query_timing_ms = _parse_query_timing_ms(d.pop("query_timing_ms")) + def _parse_repeat_index(data: object) -> int | None: + if data is None: + return data + return cast(int | None, data) + + repeat_index = _parse_repeat_index(d.pop("repeat_index")) + def _parse_score(data: object) -> float | None: if data is None: return data @@ -205,11 +245,13 @@ def _parse_tool_timing_ms(data: object) -> int | None: ai_timing_ms=ai_timing_ms, cost=cost, error_reason=error_reason, + eval_prompt_id=eval_prompt_id, expectation=expectation, id=id, prompt=prompt, query_count=query_count, query_timing_ms=query_timing_ms, + repeat_index=repeat_index, score=score, scoring_cost=scoring_cost, timing_ms=timing_ms, diff --git a/omni_python_sdk/models/eval_run_stats.py b/omni_python_sdk/models/eval_run_stats.py index 0904ba7..5a20c94 100644 --- a/omni_python_sdk/models/eval_run_stats.py +++ b/omni_python_sdk/models/eval_run_stats.py @@ -15,7 +15,7 @@ class EvalRunStats: Attributes: terminal (int): Number of per-prompt jobs that have reached a terminal state (COMPLETE, FAILED, or CANCELLED). Example: 8. - total (int): Total number of per-prompt jobs in the run. Example: 12. + total (int): Total number of jobs in the run (prompts × the repeat count). Example: 12. """ terminal: int diff --git a/omni_python_sdk/models/eval_runs_cancel_response.py b/omni_python_sdk/models/eval_runs_cancel_response.py index 9ba2680..7dd6604 100644 --- a/omni_python_sdk/models/eval_runs_cancel_response.py +++ b/omni_python_sdk/models/eval_runs_cancel_response.py @@ -19,7 +19,7 @@ class EvalRunsCancelResponse: Attributes: cancelled (int): Number of per-prompt agentic jobs that were cancelled by this request. Example: 4. run (EvalRunDetail): The newly created run with its initial results. - total (int): Total number of per-prompt jobs in the run. Example: 12. + total (int): Total number of jobs in the run (prompts × the repeat count). Example: 12. """ cancelled: int diff --git a/omni_python_sdk/models/eval_runs_create_body_run_config.py b/omni_python_sdk/models/eval_runs_create_body_run_config.py index 77bec0c..4997a66 100644 --- a/omni_python_sdk/models/eval_runs_create_body_run_config.py +++ b/omni_python_sdk/models/eval_runs_create_body_run_config.py @@ -19,9 +19,12 @@ class EvalRunsCreateBodyRunConfig: Attributes: branch_id (UUID | Unset): Optional branch ID to run against. Must be a branch of the prompt set's model. Example: 440e8400-e29b-41d4-a716-446655440006. + repeat_count (int | Unset): How many times to execute each prompt in the set (defaults to 1). Between 1 and 10; + prompts × repeats may not exceed the per-run job limit. Example: 1. """ branch_id: UUID | Unset = UNSET + repeat_count: int | Unset = UNSET additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: @@ -29,11 +32,15 @@ def to_dict(self) -> dict[str, Any]: if not isinstance(self.branch_id, Unset): branch_id = str(self.branch_id) + repeat_count = self.repeat_count + field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) field_dict.update({}) if branch_id is not UNSET: field_dict["branch_id"] = branch_id + if repeat_count is not UNSET: + field_dict["repeat_count"] = repeat_count return field_dict @@ -47,8 +54,11 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: else: branch_id = UUID(_branch_id) + repeat_count = d.pop("repeat_count", UNSET) + eval_runs_create_body_run_config = cls( branch_id=branch_id, + repeat_count=repeat_count, ) eval_runs_create_body_run_config.additional_properties = d diff --git a/omni_python_sdk/models/eval_runs_create_response.py b/omni_python_sdk/models/eval_runs_create_response.py index 3fd49ee..c4c2647 100644 --- a/omni_python_sdk/models/eval_runs_create_response.py +++ b/omni_python_sdk/models/eval_runs_create_response.py @@ -17,9 +17,9 @@ class EvalRunsCreateResponse: """ Attributes: - job_count (int): Number of per-prompt agentic jobs created for this run (one per prompt that fanned out - successfully). Enqueue onto the work queue happens after creation and is best-effort, so this count reflects - jobs created, not necessarily those successfully enqueued. Example: 12. + job_count (int): Number of agentic jobs created for this run (one per prompt execution — prompts × repeat count + — that fanned out successfully). Enqueue onto the work queue happens after creation and is best-effort, so this + count reflects jobs created, not necessarily those successfully enqueued. Example: 12. run (EvalRunDetail): The newly created run with its initial results. """ diff --git a/omni_python_sdk/models/generate_suggestions_response.py b/omni_python_sdk/models/generate_suggestions_response.py new file mode 100644 index 0000000..44a00f2 --- /dev/null +++ b/omni_python_sdk/models/generate_suggestions_response.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.generate_suggestions_response_status import ( + GenerateSuggestionsResponseStatus, + check_generate_suggestions_response_status, +) + +T = TypeVar("T", bound="GenerateSuggestionsResponse") + + +@_attrs_define +class GenerateSuggestionsResponse: + """ + Attributes: + run_id (UUID): The id of the created generation run. Poll `GET /suggestions/runs/{runId}` for status. + status (GenerateSuggestionsResponseStatus): The generation run was enqueued. Generation runs asynchronously. + """ + + run_id: UUID + status: GenerateSuggestionsResponseStatus + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + run_id = str(self.run_id) + + status: str = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "runId": run_id, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + run_id = UUID(d.pop("runId")) + + status = check_generate_suggestions_response_status(d.pop("status")) + + generate_suggestions_response = cls( + run_id=run_id, + status=status, + ) + + generate_suggestions_response.additional_properties = d + return generate_suggestions_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/generate_suggestions_response_status.py b/omni_python_sdk/models/generate_suggestions_response_status.py new file mode 100644 index 0000000..f8604bd --- /dev/null +++ b/omni_python_sdk/models/generate_suggestions_response_status.py @@ -0,0 +1,13 @@ +from typing import Literal + +GenerateSuggestionsResponseStatus = Literal["queued"] + +GENERATE_SUGGESTIONS_RESPONSE_STATUS_VALUES: set[GenerateSuggestionsResponseStatus] = { + "queued", +} + + +def check_generate_suggestions_response_status(value: str) -> GenerateSuggestionsResponseStatus: + if value in GENERATE_SUGGESTIONS_RESPONSE_STATUS_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {GENERATE_SUGGESTIONS_RESPONSE_STATUS_VALUES!r}") diff --git a/omni_python_sdk/models/models_git_create_body.py b/omni_python_sdk/models/models_git_create_body.py index 8fead04..b9580a9 100644 --- a/omni_python_sdk/models/models_git_create_body.py +++ b/omni_python_sdk/models/models_git_create_body.py @@ -35,6 +35,12 @@ class ModelsGitCreateBody: false Default: False. clone_url (str | Unset): Clone URL of the git repository. SSH (git@...) for deploy key auth, HTTPS (https://...) for token auth. Example: git@github.com:org/repo.git. + deploy_key_passphrase (str | Unset): Passphrase for deployPrivateKey when it is encrypted. Omni uses it once to + decrypt the key, then stores the key under its own encryption at rest; the passphrase itself is not retained. + deploy_private_key (str | Unset): Bring-your-own SSH deploy private key in PEM format (RSA or ED25519, as + produced by ssh-keygen), used instead of an Omni-generated keypair. On update it replaces the current key, + enabling zero-downtime rotation: authorize the matching public key with your git provider first, then set it + here. Only valid for SSH auth. git_follower (bool | Unset): If true, the shared model will be read-only. Defaults to false Default: False. git_service_provider (ModelsGitCreateBodyGitServiceProvider | Unset): The git provider type. Use "auto" for automatic detection. Defaults to "auto" Default: 'auto'. Example: auto. @@ -55,6 +61,8 @@ class ModelsGitCreateBody: base_branch: str | Unset = "main" branch_per_pull_request: bool | Unset = False clone_url: str | Unset = UNSET + deploy_key_passphrase: str | Unset = UNSET + deploy_private_key: str | Unset = UNSET git_follower: bool | Unset = False git_service_provider: ModelsGitCreateBodyGitServiceProvider | Unset = "auto" model_path: str | Unset = UNSET @@ -75,6 +83,10 @@ def to_dict(self) -> dict[str, Any]: clone_url = self.clone_url + deploy_key_passphrase = self.deploy_key_passphrase + + deploy_private_key = self.deploy_private_key + git_follower = self.git_follower git_service_provider: str | Unset = UNSET @@ -104,6 +116,10 @@ def to_dict(self) -> dict[str, Any]: field_dict["branchPerPullRequest"] = branch_per_pull_request if clone_url is not UNSET: field_dict["cloneUrl"] = clone_url + if deploy_key_passphrase is not UNSET: + field_dict["deployKeyPassphrase"] = deploy_key_passphrase + if deploy_private_key is not UNSET: + field_dict["deployPrivateKey"] = deploy_private_key if git_follower is not UNSET: field_dict["gitFollower"] = git_follower if git_service_provider is not UNSET: @@ -137,6 +153,10 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: clone_url = d.pop("cloneUrl", UNSET) + deploy_key_passphrase = d.pop("deployKeyPassphrase", UNSET) + + deploy_private_key = d.pop("deployPrivateKey", UNSET) + git_follower = d.pop("gitFollower", UNSET) _git_service_provider = d.pop("gitServiceProvider", UNSET) @@ -166,6 +186,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: base_branch=base_branch, branch_per_pull_request=branch_per_pull_request, clone_url=clone_url, + deploy_key_passphrase=deploy_key_passphrase, + deploy_private_key=deploy_private_key, git_follower=git_follower, git_service_provider=git_service_provider, model_path=model_path, diff --git a/omni_python_sdk/models/models_git_create_response.py b/omni_python_sdk/models/models_git_create_response.py index 10dc10f..bdad956 100644 --- a/omni_python_sdk/models/models_git_create_response.py +++ b/omni_python_sdk/models/models_git_create_response.py @@ -24,7 +24,8 @@ class ModelsGitCreateResponse: """ Attributes: auth_method (ModelsGitCreateResponseAuthMethod): Authentication method. "ssh" for deploy key, "https_token" for - deploy token/PAT. Example: ssh. + deploy token/PAT. "github_app" may appear for connections managed in Omni model settings; it cannot be created + or modified through this API. Example: ssh. base_branch (str): The target branch for Omni pull requests Example: main. branch_per_pull_request (bool): If true, all pull requests will create a branch in Omni, even those created outside of the tool diff --git a/omni_python_sdk/models/models_git_create_response_auth_method.py b/omni_python_sdk/models/models_git_create_response_auth_method.py index 2b8f162..68fbf16 100644 --- a/omni_python_sdk/models/models_git_create_response_auth_method.py +++ b/omni_python_sdk/models/models_git_create_response_auth_method.py @@ -1,8 +1,9 @@ from typing import Literal -ModelsGitCreateResponseAuthMethod = Literal["https_token", "ssh"] +ModelsGitCreateResponseAuthMethod = Literal["github_app", "https_token", "ssh"] MODELS_GIT_CREATE_RESPONSE_AUTH_METHOD_VALUES: set[ModelsGitCreateResponseAuthMethod] = { + "github_app", "https_token", "ssh", } diff --git a/omni_python_sdk/models/models_git_get_response.py b/omni_python_sdk/models/models_git_get_response.py index 2cd2eab..8c42ae5 100644 --- a/omni_python_sdk/models/models_git_get_response.py +++ b/omni_python_sdk/models/models_git_get_response.py @@ -24,7 +24,8 @@ class ModelsGitGetResponse: """ Attributes: auth_method (ModelsGitGetResponseAuthMethod): Authentication method. "ssh" for deploy key, "https_token" for - deploy token/PAT. Example: ssh. + deploy token/PAT. "github_app" may appear for connections managed in Omni model settings; it cannot be created + or modified through this API. Example: ssh. base_branch (str): The target branch for Omni pull requests Example: main. branch_per_pull_request (bool): If true, all pull requests will create a branch in Omni, even those created outside of the tool diff --git a/omni_python_sdk/models/models_git_get_response_auth_method.py b/omni_python_sdk/models/models_git_get_response_auth_method.py index 71daba7..6a061ed 100644 --- a/omni_python_sdk/models/models_git_get_response_auth_method.py +++ b/omni_python_sdk/models/models_git_get_response_auth_method.py @@ -1,8 +1,9 @@ from typing import Literal -ModelsGitGetResponseAuthMethod = Literal["https_token", "ssh"] +ModelsGitGetResponseAuthMethod = Literal["github_app", "https_token", "ssh"] MODELS_GIT_GET_RESPONSE_AUTH_METHOD_VALUES: set[ModelsGitGetResponseAuthMethod] = { + "github_app", "https_token", "ssh", } diff --git a/omni_python_sdk/models/models_git_update_body.py b/omni_python_sdk/models/models_git_update_body.py index d56b3af..b60b47a 100644 --- a/omni_python_sdk/models/models_git_update_body.py +++ b/omni_python_sdk/models/models_git_update_body.py @@ -31,6 +31,12 @@ class ModelsGitUpdateBody: base_branch (str | Unset): The target branch for Omni pull requests Example: main. branch_per_pull_request (bool | Unset): If true, all pull requests will create a branch in Omni clone_url (str | Unset): Clone URL of the git repository (SSH or HTTPS). Example: git@github.com:org/repo.git. + deploy_key_passphrase (str | Unset): Passphrase for deployPrivateKey when it is encrypted. Omni uses it once to + decrypt the key, then stores the key under its own encryption at rest; the passphrase itself is not retained. + deploy_private_key (str | Unset): Bring-your-own SSH deploy private key in PEM format (RSA or ED25519, as + produced by ssh-keygen), used instead of an Omni-generated keypair. On update it replaces the current key, + enabling zero-downtime rotation: authorize the matching public key with your git provider first, then set it + here. Only valid for SSH auth. git_follower (bool | Unset): If true, the shared model will be read-only git_service_provider (ModelsGitUpdateBodyGitServiceProvider | Unset): The git provider type Example: github. model_path (str | Unset): Path to model files in the repository Example: my_model. @@ -47,6 +53,8 @@ class ModelsGitUpdateBody: base_branch: str | Unset = UNSET branch_per_pull_request: bool | Unset = UNSET clone_url: str | Unset = UNSET + deploy_key_passphrase: str | Unset = UNSET + deploy_private_key: str | Unset = UNSET git_follower: bool | Unset = UNSET git_service_provider: ModelsGitUpdateBodyGitServiceProvider | Unset = UNSET model_path: str | Unset = UNSET @@ -67,6 +75,10 @@ def to_dict(self) -> dict[str, Any]: clone_url = self.clone_url + deploy_key_passphrase = self.deploy_key_passphrase + + deploy_private_key = self.deploy_private_key + git_follower = self.git_follower git_service_provider: str | Unset = UNSET @@ -96,6 +108,10 @@ def to_dict(self) -> dict[str, Any]: field_dict["branchPerPullRequest"] = branch_per_pull_request if clone_url is not UNSET: field_dict["cloneUrl"] = clone_url + if deploy_key_passphrase is not UNSET: + field_dict["deployKeyPassphrase"] = deploy_key_passphrase + if deploy_private_key is not UNSET: + field_dict["deployPrivateKey"] = deploy_private_key if git_follower is not UNSET: field_dict["gitFollower"] = git_follower if git_service_provider is not UNSET: @@ -129,6 +145,10 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: clone_url = d.pop("cloneUrl", UNSET) + deploy_key_passphrase = d.pop("deployKeyPassphrase", UNSET) + + deploy_private_key = d.pop("deployPrivateKey", UNSET) + git_follower = d.pop("gitFollower", UNSET) _git_service_provider = d.pop("gitServiceProvider", UNSET) @@ -158,6 +178,8 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: base_branch=base_branch, branch_per_pull_request=branch_per_pull_request, clone_url=clone_url, + deploy_key_passphrase=deploy_key_passphrase, + deploy_private_key=deploy_private_key, git_follower=git_follower, git_service_provider=git_service_provider, model_path=model_path, diff --git a/omni_python_sdk/models/models_git_update_response.py b/omni_python_sdk/models/models_git_update_response.py index b7340e1..cf77748 100644 --- a/omni_python_sdk/models/models_git_update_response.py +++ b/omni_python_sdk/models/models_git_update_response.py @@ -24,7 +24,8 @@ class ModelsGitUpdateResponse: """ Attributes: auth_method (ModelsGitUpdateResponseAuthMethod): Authentication method. "ssh" for deploy key, "https_token" for - deploy token/PAT. Example: ssh. + deploy token/PAT. "github_app" may appear for connections managed in Omni model settings; it cannot be created + or modified through this API. Example: ssh. base_branch (str): The target branch for Omni pull requests Example: main. branch_per_pull_request (bool): If true, all pull requests will create a branch in Omni, even those created outside of the tool diff --git a/omni_python_sdk/models/models_git_update_response_auth_method.py b/omni_python_sdk/models/models_git_update_response_auth_method.py index 78010a4..362aa34 100644 --- a/omni_python_sdk/models/models_git_update_response_auth_method.py +++ b/omni_python_sdk/models/models_git_update_response_auth_method.py @@ -1,8 +1,9 @@ from typing import Literal -ModelsGitUpdateResponseAuthMethod = Literal["https_token", "ssh"] +ModelsGitUpdateResponseAuthMethod = Literal["github_app", "https_token", "ssh"] MODELS_GIT_UPDATE_RESPONSE_AUTH_METHOD_VALUES: set[ModelsGitUpdateResponseAuthMethod] = { + "github_app", "https_token", "ssh", } diff --git a/omni_python_sdk/models/query_run_response.py b/omni_python_sdk/models/query_run_response.py deleted file mode 100644 index 94ec633..0000000 --- a/omni_python_sdk/models/query_run_response.py +++ /dev/null @@ -1,84 +0,0 @@ -from __future__ import annotations - -from collections.abc import Mapping -from typing import Any, TypeVar, cast - -from attrs import define as _attrs_define -from attrs import field as _attrs_field - -from ..types import UNSET, Unset - -T = TypeVar("T", bound="QueryRunResponse") - - -@_attrs_define -class QueryRunResponse: - """ - Attributes: - completed_queries (list[Any] | Unset): Queries that completed synchronously with their results. - job_ids (list[str] | Unset): Job IDs for queries running asynchronously. Use /api/v1/query/wait to poll for - results. Example: ['job_abc123', 'job_def456']. - plan (Any | Unset): Query execution plan (only present if planOnly is true). - """ - - completed_queries: list[Any] | Unset = UNSET - job_ids: list[str] | Unset = UNSET - plan: Any | Unset = UNSET - additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) - - def to_dict(self) -> dict[str, Any]: - completed_queries: list[Any] | Unset = UNSET - if not isinstance(self.completed_queries, Unset): - completed_queries = self.completed_queries - - job_ids: list[str] | Unset = UNSET - if not isinstance(self.job_ids, Unset): - job_ids = self.job_ids - - plan = self.plan - - field_dict: dict[str, Any] = {} - field_dict.update(self.additional_properties) - field_dict.update({}) - if completed_queries is not UNSET: - field_dict["completedQueries"] = completed_queries - if job_ids is not UNSET: - field_dict["jobIds"] = job_ids - if plan is not UNSET: - field_dict["plan"] = plan - - return field_dict - - @classmethod - def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: - d = dict(src_dict) - completed_queries = cast(list[Any], d.pop("completedQueries", UNSET)) - - job_ids = cast(list[str], d.pop("jobIds", UNSET)) - - plan = d.pop("plan", UNSET) - - query_run_response = cls( - completed_queries=completed_queries, - job_ids=job_ids, - plan=plan, - ) - - query_run_response.additional_properties = d - return query_run_response - - @property - def additional_keys(self) -> list[str]: - return list(self.additional_properties.keys()) - - def __getitem__(self, key: str) -> Any: - return self.additional_properties[key] - - def __setitem__(self, key: str, value: Any) -> None: - self.additional_properties[key] = value - - def __delitem__(self, key: str) -> None: - del self.additional_properties[key] - - def __contains__(self, key: str) -> bool: - return key in self.additional_properties diff --git a/omni_python_sdk/models/query_wait_response.py b/omni_python_sdk/models/query_run_response_200_item.py similarity index 62% rename from omni_python_sdk/models/query_wait_response.py rename to omni_python_sdk/models/query_run_response_200_item.py index 2496192..68f27a7 100644 --- a/omni_python_sdk/models/query_wait_response.py +++ b/omni_python_sdk/models/query_run_response_200_item.py @@ -1,48 +1,34 @@ from __future__ import annotations from collections.abc import Mapping -from typing import Any, TypeVar, cast +from typing import Any, TypeVar from attrs import define as _attrs_define from attrs import field as _attrs_field -T = TypeVar("T", bound="QueryWaitResponse") +T = TypeVar("T", bound="QueryRunResponse200Item") @_attrs_define -class QueryWaitResponse: - """ - Attributes: - results (list[Any]): Array of completed query results. Each result contains the query data or an error. - """ +class QueryRunResponse200Item: + """ """ - results: list[Any] additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) def to_dict(self) -> dict[str, Any]: - results = self.results field_dict: dict[str, Any] = {} field_dict.update(self.additional_properties) - field_dict.update( - { - "results": results, - } - ) return field_dict @classmethod def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: d = dict(src_dict) - results = cast(list[Any], d.pop("results")) + query_run_response_200_item = cls() - query_wait_response = cls( - results=results, - ) - - query_wait_response.additional_properties = d - return query_wait_response + query_run_response_200_item.additional_properties = d + return query_run_response_200_item @property def additional_keys(self) -> list[str]: diff --git a/omni_python_sdk/models/query_stream_footer_line.py b/omni_python_sdk/models/query_stream_footer_line.py new file mode 100644 index 0000000..562d9d2 --- /dev/null +++ b/omni_python_sdk/models/query_stream_footer_line.py @@ -0,0 +1,77 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.query_stream_footer_line_timed_out import ( + QueryStreamFooterLineTimedOut, + check_query_stream_footer_line_timed_out, +) + +T = TypeVar("T", bound="QueryStreamFooterLine") + + +@_attrs_define +class QueryStreamFooterLine: + """Last line of the stream. + + Attributes: + remaining_job_ids (list[str]): Job IDs that had not completed when the wait window elapsed. Poll + /api/v1/query/wait with these IDs until the list is empty. + timed_out (QueryStreamFooterLineTimedOut): Whether the wait window elapsed before every job completed. Note: a + string ("true"/"false"), not a boolean. Example: false. + """ + + remaining_job_ids: list[str] + timed_out: QueryStreamFooterLineTimedOut + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + remaining_job_ids = self.remaining_job_ids + + timed_out: str = self.timed_out + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "remaining_job_ids": remaining_job_ids, + "timed_out": timed_out, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + remaining_job_ids = cast(list[str], d.pop("remaining_job_ids")) + + timed_out = check_query_stream_footer_line_timed_out(d.pop("timed_out")) + + query_stream_footer_line = cls( + remaining_job_ids=remaining_job_ids, + timed_out=timed_out, + ) + + query_stream_footer_line.additional_properties = d + return query_stream_footer_line + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_stream_footer_line_timed_out.py b/omni_python_sdk/models/query_stream_footer_line_timed_out.py new file mode 100644 index 0000000..77396bd --- /dev/null +++ b/omni_python_sdk/models/query_stream_footer_line_timed_out.py @@ -0,0 +1,14 @@ +from typing import Literal + +QueryStreamFooterLineTimedOut = Literal["false", "true"] + +QUERY_STREAM_FOOTER_LINE_TIMED_OUT_VALUES: set[QueryStreamFooterLineTimedOut] = { + "false", + "true", +} + + +def check_query_stream_footer_line_timed_out(value: str) -> QueryStreamFooterLineTimedOut: + if value in QUERY_STREAM_FOOTER_LINE_TIMED_OUT_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {QUERY_STREAM_FOOTER_LINE_TIMED_OUT_VALUES!r}") diff --git a/omni_python_sdk/models/query_stream_job_line.py b/omni_python_sdk/models/query_stream_job_line.py new file mode 100644 index 0000000..e45970b --- /dev/null +++ b/omni_python_sdk/models/query_stream_job_line.py @@ -0,0 +1,245 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..types import UNSET, Unset + +if TYPE_CHECKING: + from ..models.query_stream_job_line_column_name_mapping import QueryStreamJobLineColumnNameMapping + from ..models.query_stream_job_line_stream_stats import QueryStreamJobLineStreamStats + from ..models.query_stream_job_line_used_keys import QueryStreamJobLineUsedKeys + + +T = TypeVar("T", bound="QueryStreamJobLine") + + +@_attrs_define +class QueryStreamJobLine: + """Per-job line emitted as each job reaches a terminal state. A completed job carries the result set as base64-encoded + Arrow IPC in `result`; a failed job carries `error_type` and `error_message` instead. + + Attributes: + job_id (str): ID of the query job this line reports on. + status (str): Job status. Known values include COMPLETE, ERROR, FAILED, and MISSING; new values may be added + over time. Example: COMPLETE. + cache_metadata (Any | Unset): Cache metadata for the result (row count, byte size, freshness timestamps, requery + plan key). + client_result_id (str | Unset): Client-supplied result ID echoed back for correlating jobs to queries. + column_name_mapping (QueryStreamJobLineColumnNameMapping | Unset): + error (Any | Unset): Structured error details, e.g. an OAuth re-authentication requirement. + error_message (str | Unset): Human-readable error message. Present on failed jobs. Example: No such view + "order_items". + error_type (str | Unset): Machine-readable error category (e.g. PLAN, SQL). Present on failed jobs. Example: + PLAN. + kill_reason (str | Unset): Why the job was killed, when it was cancelled. + query (Any | Unset): The query that was executed. + requery_fallback_sql (str | Unset): + requery_sql (str | Unset): SQL to re-query the cached result set, when the result supports requery. + requery_table_name (str | Unset): + result (str | Unset): Result rows as a base64-encoded Arrow IPC stream. Present on completed jobs. Decode with + any Arrow IPC reader and use summary.fields to interpret the columns. + stream_stats (QueryStreamJobLineStreamStats | Unset): Server-side streaming latency stats, in milliseconds. + summary (Any | Unset): Execution summary. summary.fields maps field names to their metadata and is needed to + interpret the decoded Arrow table; also carries the generated SQL and cache type. + used_keys (QueryStreamJobLineUsedKeys | Unset): + """ + + job_id: str + status: str + cache_metadata: Any | Unset = UNSET + client_result_id: str | Unset = UNSET + column_name_mapping: QueryStreamJobLineColumnNameMapping | Unset = UNSET + error: Any | Unset = UNSET + error_message: str | Unset = UNSET + error_type: str | Unset = UNSET + kill_reason: str | Unset = UNSET + query: Any | Unset = UNSET + requery_fallback_sql: str | Unset = UNSET + requery_sql: str | Unset = UNSET + requery_table_name: str | Unset = UNSET + result: str | Unset = UNSET + stream_stats: QueryStreamJobLineStreamStats | Unset = UNSET + summary: Any | Unset = UNSET + used_keys: QueryStreamJobLineUsedKeys | Unset = UNSET + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + job_id = self.job_id + + status = self.status + + cache_metadata = self.cache_metadata + + client_result_id = self.client_result_id + + column_name_mapping: dict[str, Any] | Unset = UNSET + if not isinstance(self.column_name_mapping, Unset): + column_name_mapping = self.column_name_mapping.to_dict() + + error = self.error + + error_message = self.error_message + + error_type = self.error_type + + kill_reason = self.kill_reason + + query = self.query + + requery_fallback_sql = self.requery_fallback_sql + + requery_sql = self.requery_sql + + requery_table_name = self.requery_table_name + + result = self.result + + stream_stats: dict[str, Any] | Unset = UNSET + if not isinstance(self.stream_stats, Unset): + stream_stats = self.stream_stats.to_dict() + + summary = self.summary + + used_keys: dict[str, Any] | Unset = UNSET + if not isinstance(self.used_keys, Unset): + used_keys = self.used_keys.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "job_id": job_id, + "status": status, + } + ) + if cache_metadata is not UNSET: + field_dict["cache_metadata"] = cache_metadata + if client_result_id is not UNSET: + field_dict["client_result_id"] = client_result_id + if column_name_mapping is not UNSET: + field_dict["column_name_mapping"] = column_name_mapping + if error is not UNSET: + field_dict["error"] = error + if error_message is not UNSET: + field_dict["error_message"] = error_message + if error_type is not UNSET: + field_dict["error_type"] = error_type + if kill_reason is not UNSET: + field_dict["kill_reason"] = kill_reason + if query is not UNSET: + field_dict["query"] = query + if requery_fallback_sql is not UNSET: + field_dict["requery_fallback_sql"] = requery_fallback_sql + if requery_sql is not UNSET: + field_dict["requery_sql"] = requery_sql + if requery_table_name is not UNSET: + field_dict["requery_table_name"] = requery_table_name + if result is not UNSET: + field_dict["result"] = result + if stream_stats is not UNSET: + field_dict["stream_stats"] = stream_stats + if summary is not UNSET: + field_dict["summary"] = summary + if used_keys is not UNSET: + field_dict["used_keys"] = used_keys + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.query_stream_job_line_column_name_mapping import QueryStreamJobLineColumnNameMapping + from ..models.query_stream_job_line_stream_stats import QueryStreamJobLineStreamStats + from ..models.query_stream_job_line_used_keys import QueryStreamJobLineUsedKeys + + d = dict(src_dict) + job_id = d.pop("job_id") + + status = d.pop("status") + + cache_metadata = d.pop("cache_metadata", UNSET) + + client_result_id = d.pop("client_result_id", UNSET) + + _column_name_mapping = d.pop("column_name_mapping", UNSET) + column_name_mapping: QueryStreamJobLineColumnNameMapping | Unset + if isinstance(_column_name_mapping, Unset): + column_name_mapping = UNSET + else: + column_name_mapping = QueryStreamJobLineColumnNameMapping.from_dict(_column_name_mapping) + + error = d.pop("error", UNSET) + + error_message = d.pop("error_message", UNSET) + + error_type = d.pop("error_type", UNSET) + + kill_reason = d.pop("kill_reason", UNSET) + + query = d.pop("query", UNSET) + + requery_fallback_sql = d.pop("requery_fallback_sql", UNSET) + + requery_sql = d.pop("requery_sql", UNSET) + + requery_table_name = d.pop("requery_table_name", UNSET) + + result = d.pop("result", UNSET) + + _stream_stats = d.pop("stream_stats", UNSET) + stream_stats: QueryStreamJobLineStreamStats | Unset + if isinstance(_stream_stats, Unset): + stream_stats = UNSET + else: + stream_stats = QueryStreamJobLineStreamStats.from_dict(_stream_stats) + + summary = d.pop("summary", UNSET) + + _used_keys = d.pop("used_keys", UNSET) + used_keys: QueryStreamJobLineUsedKeys | Unset + if isinstance(_used_keys, Unset): + used_keys = UNSET + else: + used_keys = QueryStreamJobLineUsedKeys.from_dict(_used_keys) + + query_stream_job_line = cls( + job_id=job_id, + status=status, + cache_metadata=cache_metadata, + client_result_id=client_result_id, + column_name_mapping=column_name_mapping, + error=error, + error_message=error_message, + error_type=error_type, + kill_reason=kill_reason, + query=query, + requery_fallback_sql=requery_fallback_sql, + requery_sql=requery_sql, + requery_table_name=requery_table_name, + result=result, + stream_stats=stream_stats, + summary=summary, + used_keys=used_keys, + ) + + query_stream_job_line.additional_properties = d + return query_stream_job_line + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_stream_job_line_column_name_mapping.py b/omni_python_sdk/models/query_stream_job_line_column_name_mapping.py new file mode 100644 index 0000000..226c0b9 --- /dev/null +++ b/omni_python_sdk/models/query_stream_job_line_column_name_mapping.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="QueryStreamJobLineColumnNameMapping") + + +@_attrs_define +class QueryStreamJobLineColumnNameMapping: + """ """ + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + query_stream_job_line_column_name_mapping = cls() + + query_stream_job_line_column_name_mapping.additional_properties = d + return query_stream_job_line_column_name_mapping + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_stream_job_line_stream_stats.py b/omni_python_sdk/models/query_stream_job_line_stream_stats.py new file mode 100644 index 0000000..b9662d2 --- /dev/null +++ b/omni_python_sdk/models/query_stream_job_line_stream_stats.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="QueryStreamJobLineStreamStats") + + +@_attrs_define +class QueryStreamJobLineStreamStats: + """Server-side streaming latency stats, in milliseconds.""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + query_stream_job_line_stream_stats = cls() + + query_stream_job_line_stream_stats.additional_properties = d + return query_stream_job_line_stream_stats + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_stream_job_line_used_keys.py b/omni_python_sdk/models/query_stream_job_line_used_keys.py new file mode 100644 index 0000000..859aa82 --- /dev/null +++ b/omni_python_sdk/models/query_stream_job_line_used_keys.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="QueryStreamJobLineUsedKeys") + + +@_attrs_define +class QueryStreamJobLineUsedKeys: + """ """ + + additional_properties: dict[str, str] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + query_stream_job_line_used_keys = cls() + + query_stream_job_line_used_keys.additional_properties = d + return query_stream_job_line_used_keys + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> str: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: str) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_stream_jobs_submitted_line.py b/omni_python_sdk/models/query_stream_jobs_submitted_line.py new file mode 100644 index 0000000..1a43d17 --- /dev/null +++ b/omni_python_sdk/models/query_stream_jobs_submitted_line.py @@ -0,0 +1,69 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.query_stream_jobs_submitted_line_jobs_submitted import QueryStreamJobsSubmittedLineJobsSubmitted + + +T = TypeVar("T", bound="QueryStreamJobsSubmittedLine") + + +@_attrs_define +class QueryStreamJobsSubmittedLine: + """First line of the query/run stream: the jobs accepted for execution. + + Attributes: + jobs_submitted (QueryStreamJobsSubmittedLineJobsSubmitted): Map of submitted job ID to the client result ID for + that job (null when the job has no client result ID). Job IDs are the keys to poll via /api/v1/query/wait. + """ + + jobs_submitted: QueryStreamJobsSubmittedLineJobsSubmitted + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + jobs_submitted = self.jobs_submitted.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "jobs_submitted": jobs_submitted, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.query_stream_jobs_submitted_line_jobs_submitted import QueryStreamJobsSubmittedLineJobsSubmitted + + d = dict(src_dict) + jobs_submitted = QueryStreamJobsSubmittedLineJobsSubmitted.from_dict(d.pop("jobs_submitted")) + + query_stream_jobs_submitted_line = cls( + jobs_submitted=jobs_submitted, + ) + + query_stream_jobs_submitted_line.additional_properties = d + return query_stream_jobs_submitted_line + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/query_stream_jobs_submitted_line_jobs_submitted.py b/omni_python_sdk/models/query_stream_jobs_submitted_line_jobs_submitted.py new file mode 100644 index 0000000..9b0c7ac --- /dev/null +++ b/omni_python_sdk/models/query_stream_jobs_submitted_line_jobs_submitted.py @@ -0,0 +1,75 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="QueryStreamJobsSubmittedLineJobsSubmitted") + + +@_attrs_define +class QueryStreamJobsSubmittedLineJobsSubmitted: + """Map of submitted job ID to the client result ID for that job (null when the job has no client result ID). Job IDs + are the keys to poll via /api/v1/query/wait. + + """ + + additional_properties: dict[str, None | UUID] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + for prop_name, prop in self.additional_properties.items(): + if isinstance(prop, UUID): + field_dict[prop_name] = str(prop) + else: + field_dict[prop_name] = prop + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + query_stream_jobs_submitted_line_jobs_submitted = cls() + + additional_properties = {} + for prop_name, prop_dict in d.items(): + + def _parse_additional_property(data: object) -> None | UUID: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + additional_property_type_0 = UUID(data) + + return additional_property_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | UUID, data) + + additional_property = _parse_additional_property(prop_dict) + + additional_properties[prop_name] = additional_property + + query_stream_jobs_submitted_line_jobs_submitted.additional_properties = additional_properties + return query_stream_jobs_submitted_line_jobs_submitted + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> None | UUID: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: None | UUID) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/suggestion_run.py b/omni_python_sdk/models/suggestion_run.py new file mode 100644 index 0000000..b783903 --- /dev/null +++ b/omni_python_sdk/models/suggestion_run.py @@ -0,0 +1,204 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.suggestion_run_status import SuggestionRunStatus, check_suggestion_run_status +from ..models.suggestion_run_trigger_source import SuggestionRunTriggerSource, check_suggestion_run_trigger_source + +if TYPE_CHECKING: + from ..models.suggestion_run_error_type_0 import SuggestionRunErrorType0 + from ..models.suggestion_run_triggered_by_type_0 import SuggestionRunTriggeredByType0 + + +T = TypeVar("T", bound="SuggestionRun") + + +@_attrs_define +class SuggestionRun: + """ + Attributes: + completed_at (datetime.datetime | None): ISO 8601 timestamp when the run reached a terminal state. + created_at (datetime.datetime): ISO 8601 timestamp when the run was created (queued). + error (None | SuggestionRunErrorType0): Failure details when `status` is `failed`; null otherwise. + execution_started_at (datetime.datetime | None): ISO 8601 timestamp when the worker started executing; null + while queued. + id (UUID): The run id. + status (SuggestionRunStatus): Run status. Terminal states are `complete` and `failed`. + trigger_source (SuggestionRunTriggerSource): Whether the run was triggered manually or by the schedule. + triggered_by (None | SuggestionRunTriggeredByType0): The user who triggered a manual run; null for scheduled + runs. + """ + + completed_at: datetime.datetime | None + created_at: datetime.datetime + error: None | SuggestionRunErrorType0 + execution_started_at: datetime.datetime | None + id: UUID + status: SuggestionRunStatus + trigger_source: SuggestionRunTriggerSource + triggered_by: None | SuggestionRunTriggeredByType0 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.suggestion_run_error_type_0 import SuggestionRunErrorType0 + from ..models.suggestion_run_triggered_by_type_0 import SuggestionRunTriggeredByType0 + + completed_at: None | str + if isinstance(self.completed_at, datetime.datetime): + completed_at = self.completed_at.isoformat() + else: + completed_at = self.completed_at + + created_at = self.created_at.isoformat() + + error: dict[str, Any] | None + if isinstance(self.error, SuggestionRunErrorType0): + error = self.error.to_dict() + else: + error = self.error + + execution_started_at: None | str + if isinstance(self.execution_started_at, datetime.datetime): + execution_started_at = self.execution_started_at.isoformat() + else: + execution_started_at = self.execution_started_at + + id = str(self.id) + + status: str = self.status + + trigger_source: str = self.trigger_source + + triggered_by: dict[str, Any] | None + if isinstance(self.triggered_by, SuggestionRunTriggeredByType0): + triggered_by = self.triggered_by.to_dict() + else: + triggered_by = self.triggered_by + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "completedAt": completed_at, + "createdAt": created_at, + "error": error, + "executionStartedAt": execution_started_at, + "id": id, + "status": status, + "triggerSource": trigger_source, + "triggeredBy": triggered_by, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.suggestion_run_error_type_0 import SuggestionRunErrorType0 + from ..models.suggestion_run_triggered_by_type_0 import SuggestionRunTriggeredByType0 + + d = dict(src_dict) + + def _parse_completed_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + completed_at_type_0 = datetime.datetime.fromisoformat(data) + + return completed_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + completed_at = _parse_completed_at(d.pop("completedAt")) + + created_at = datetime.datetime.fromisoformat(d.pop("createdAt")) + + def _parse_error(data: object) -> None | SuggestionRunErrorType0: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + error_type_0 = SuggestionRunErrorType0.from_dict(data) + + return error_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | SuggestionRunErrorType0, data) + + error = _parse_error(d.pop("error")) + + def _parse_execution_started_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + execution_started_at_type_0 = datetime.datetime.fromisoformat(data) + + return execution_started_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + execution_started_at = _parse_execution_started_at(d.pop("executionStartedAt")) + + id = UUID(d.pop("id")) + + status = check_suggestion_run_status(d.pop("status")) + + trigger_source = check_suggestion_run_trigger_source(d.pop("triggerSource")) + + def _parse_triggered_by(data: object) -> None | SuggestionRunTriggeredByType0: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + triggered_by_type_0 = SuggestionRunTriggeredByType0.from_dict(data) + + return triggered_by_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | SuggestionRunTriggeredByType0, data) + + triggered_by = _parse_triggered_by(d.pop("triggeredBy")) + + suggestion_run = cls( + completed_at=completed_at, + created_at=created_at, + error=error, + execution_started_at=execution_started_at, + id=id, + status=status, + trigger_source=trigger_source, + triggered_by=triggered_by, + ) + + suggestion_run.additional_properties = d + return suggestion_run + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/suggestion_run_error_type_0.py b/omni_python_sdk/models/suggestion_run_error_type_0.py new file mode 100644 index 0000000..3f7e3eb --- /dev/null +++ b/omni_python_sdk/models/suggestion_run_error_type_0.py @@ -0,0 +1,47 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SuggestionRunErrorType0") + + +@_attrs_define +class SuggestionRunErrorType0: + """Failure details when `status` is `failed`; null otherwise.""" + + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + suggestion_run_error_type_0 = cls() + + suggestion_run_error_type_0.additional_properties = d + return suggestion_run_error_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/suggestion_run_latest_response.py b/omni_python_sdk/models/suggestion_run_latest_response.py new file mode 100644 index 0000000..90bfe7f --- /dev/null +++ b/omni_python_sdk/models/suggestion_run_latest_response.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +if TYPE_CHECKING: + from ..models.suggestion_run_latest_response_run import SuggestionRunLatestResponseRun + + +T = TypeVar("T", bound="SuggestionRunLatestResponse") + + +@_attrs_define +class SuggestionRunLatestResponse: + """ + Attributes: + run (SuggestionRunLatestResponseRun): + """ + + run: SuggestionRunLatestResponseRun + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + run = self.run.to_dict() + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "run": run, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.suggestion_run_latest_response_run import SuggestionRunLatestResponseRun + + d = dict(src_dict) + run = SuggestionRunLatestResponseRun.from_dict(d.pop("run")) + + suggestion_run_latest_response = cls( + run=run, + ) + + suggestion_run_latest_response.additional_properties = d + return suggestion_run_latest_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/suggestion_run_latest_response_run.py b/omni_python_sdk/models/suggestion_run_latest_response_run.py new file mode 100644 index 0000000..d57d6be --- /dev/null +++ b/omni_python_sdk/models/suggestion_run_latest_response_run.py @@ -0,0 +1,204 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import TYPE_CHECKING, Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +from ..models.suggestion_run_status import SuggestionRunStatus, check_suggestion_run_status +from ..models.suggestion_run_trigger_source import SuggestionRunTriggerSource, check_suggestion_run_trigger_source + +if TYPE_CHECKING: + from ..models.suggestion_run_error_type_0 import SuggestionRunErrorType0 + from ..models.suggestion_run_triggered_by_type_0 import SuggestionRunTriggeredByType0 + + +T = TypeVar("T", bound="SuggestionRunLatestResponseRun") + + +@_attrs_define +class SuggestionRunLatestResponseRun: + """ + Attributes: + completed_at (datetime.datetime | None): ISO 8601 timestamp when the run reached a terminal state. + created_at (datetime.datetime): ISO 8601 timestamp when the run was created (queued). + error (None | SuggestionRunErrorType0): Failure details when `status` is `failed`; null otherwise. + execution_started_at (datetime.datetime | None): ISO 8601 timestamp when the worker started executing; null + while queued. + id (UUID): The run id. + status (SuggestionRunStatus): Run status. Terminal states are `complete` and `failed`. + trigger_source (SuggestionRunTriggerSource): Whether the run was triggered manually or by the schedule. + triggered_by (None | SuggestionRunTriggeredByType0): The user who triggered a manual run; null for scheduled + runs. + """ + + completed_at: datetime.datetime | None + created_at: datetime.datetime + error: None | SuggestionRunErrorType0 + execution_started_at: datetime.datetime | None + id: UUID + status: SuggestionRunStatus + trigger_source: SuggestionRunTriggerSource + triggered_by: None | SuggestionRunTriggeredByType0 + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + from ..models.suggestion_run_error_type_0 import SuggestionRunErrorType0 + from ..models.suggestion_run_triggered_by_type_0 import SuggestionRunTriggeredByType0 + + completed_at: None | str + if isinstance(self.completed_at, datetime.datetime): + completed_at = self.completed_at.isoformat() + else: + completed_at = self.completed_at + + created_at = self.created_at.isoformat() + + error: dict[str, Any] | None + if isinstance(self.error, SuggestionRunErrorType0): + error = self.error.to_dict() + else: + error = self.error + + execution_started_at: None | str + if isinstance(self.execution_started_at, datetime.datetime): + execution_started_at = self.execution_started_at.isoformat() + else: + execution_started_at = self.execution_started_at + + id = str(self.id) + + status: str = self.status + + trigger_source: str = self.trigger_source + + triggered_by: dict[str, Any] | None + if isinstance(self.triggered_by, SuggestionRunTriggeredByType0): + triggered_by = self.triggered_by.to_dict() + else: + triggered_by = self.triggered_by + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "completedAt": completed_at, + "createdAt": created_at, + "error": error, + "executionStartedAt": execution_started_at, + "id": id, + "status": status, + "triggerSource": trigger_source, + "triggeredBy": triggered_by, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + from ..models.suggestion_run_error_type_0 import SuggestionRunErrorType0 + from ..models.suggestion_run_triggered_by_type_0 import SuggestionRunTriggeredByType0 + + d = dict(src_dict) + + def _parse_completed_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + completed_at_type_0 = datetime.datetime.fromisoformat(data) + + return completed_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + completed_at = _parse_completed_at(d.pop("completedAt")) + + created_at = datetime.datetime.fromisoformat(d.pop("createdAt")) + + def _parse_error(data: object) -> None | SuggestionRunErrorType0: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + error_type_0 = SuggestionRunErrorType0.from_dict(data) + + return error_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | SuggestionRunErrorType0, data) + + error = _parse_error(d.pop("error")) + + def _parse_execution_started_at(data: object) -> datetime.datetime | None: + if data is None: + return data + try: + if not isinstance(data, str): + raise TypeError() + execution_started_at_type_0 = datetime.datetime.fromisoformat(data) + + return execution_started_at_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(datetime.datetime | None, data) + + execution_started_at = _parse_execution_started_at(d.pop("executionStartedAt")) + + id = UUID(d.pop("id")) + + status = check_suggestion_run_status(d.pop("status")) + + trigger_source = check_suggestion_run_trigger_source(d.pop("triggerSource")) + + def _parse_triggered_by(data: object) -> None | SuggestionRunTriggeredByType0: + if data is None: + return data + try: + if not isinstance(data, dict): + raise TypeError() + triggered_by_type_0 = SuggestionRunTriggeredByType0.from_dict(data) + + return triggered_by_type_0 + except (TypeError, ValueError, AttributeError, KeyError): + pass + return cast(None | SuggestionRunTriggeredByType0, data) + + triggered_by = _parse_triggered_by(d.pop("triggeredBy")) + + suggestion_run_latest_response_run = cls( + completed_at=completed_at, + created_at=created_at, + error=error, + execution_started_at=execution_started_at, + id=id, + status=status, + trigger_source=trigger_source, + triggered_by=triggered_by, + ) + + suggestion_run_latest_response_run.additional_properties = d + return suggestion_run_latest_response_run + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/suggestion_run_status.py b/omni_python_sdk/models/suggestion_run_status.py new file mode 100644 index 0000000..7d15c2a --- /dev/null +++ b/omni_python_sdk/models/suggestion_run_status.py @@ -0,0 +1,16 @@ +from typing import Literal + +SuggestionRunStatus = Literal["complete", "executing", "failed", "queued"] + +SUGGESTION_RUN_STATUS_VALUES: set[SuggestionRunStatus] = { + "complete", + "executing", + "failed", + "queued", +} + + +def check_suggestion_run_status(value: str) -> SuggestionRunStatus: + if value in SUGGESTION_RUN_STATUS_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SUGGESTION_RUN_STATUS_VALUES!r}") diff --git a/omni_python_sdk/models/suggestion_run_trigger_source.py b/omni_python_sdk/models/suggestion_run_trigger_source.py new file mode 100644 index 0000000..674782f --- /dev/null +++ b/omni_python_sdk/models/suggestion_run_trigger_source.py @@ -0,0 +1,14 @@ +from typing import Literal + +SuggestionRunTriggerSource = Literal["manual", "scheduled"] + +SUGGESTION_RUN_TRIGGER_SOURCE_VALUES: set[SuggestionRunTriggerSource] = { + "manual", + "scheduled", +} + + +def check_suggestion_run_trigger_source(value: str) -> SuggestionRunTriggerSource: + if value in SUGGESTION_RUN_TRIGGER_SOURCE_VALUES: + return value + raise TypeError(f"Unexpected value {value!r}. Expected one of {SUGGESTION_RUN_TRIGGER_SOURCE_VALUES!r}") diff --git a/omni_python_sdk/models/suggestion_run_triggered_by_type_0.py b/omni_python_sdk/models/suggestion_run_triggered_by_type_0.py new file mode 100644 index 0000000..cc4b46f --- /dev/null +++ b/omni_python_sdk/models/suggestion_run_triggered_by_type_0.py @@ -0,0 +1,78 @@ +from __future__ import annotations + +from collections.abc import Mapping +from typing import Any, TypeVar, cast +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SuggestionRunTriggeredByType0") + + +@_attrs_define +class SuggestionRunTriggeredByType0: + """The user who triggered a manual run; null for scheduled runs. + + Attributes: + name (None | str): + user_id (UUID): + """ + + name: None | str + user_id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + name: None | str + name = self.name + + user_id = str(self.user_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "name": name, + "userId": user_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + + def _parse_name(data: object) -> None | str: + if data is None: + return data + return cast(None | str, data) + + name = _parse_name(d.pop("name")) + + user_id = UUID(d.pop("userId")) + + suggestion_run_triggered_by_type_0 = cls( + name=name, + user_id=user_id, + ) + + suggestion_run_triggered_by_type_0.additional_properties = d + return suggestion_run_triggered_by_type_0 + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/omni_python_sdk/models/suggestions_cooldown_response.py b/omni_python_sdk/models/suggestions_cooldown_response.py new file mode 100644 index 0000000..047b8da --- /dev/null +++ b/omni_python_sdk/models/suggestions_cooldown_response.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import Any, TypeVar + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="SuggestionsCooldownResponse") + + +@_attrs_define +class SuggestionsCooldownResponse: + """ + Attributes: + detail (str): Human-readable error message. + last_completed_at (datetime.datetime): When the most recent run completed. + retry_after_seconds (int): Seconds to wait before a new run is allowed. + status (int): Example: 429. + """ + + detail: str + last_completed_at: datetime.datetime + retry_after_seconds: int + status: int + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + detail = self.detail + + last_completed_at = self.last_completed_at.isoformat() + + retry_after_seconds = self.retry_after_seconds + + status = self.status + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "detail": detail, + "lastCompletedAt": last_completed_at, + "retryAfterSeconds": retry_after_seconds, + "status": status, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + detail = d.pop("detail") + + last_completed_at = datetime.datetime.fromisoformat(d.pop("lastCompletedAt")) + + retry_after_seconds = d.pop("retryAfterSeconds") + + status = d.pop("status") + + suggestions_cooldown_response = cls( + detail=detail, + last_completed_at=last_completed_at, + retry_after_seconds=retry_after_seconds, + status=status, + ) + + suggestions_cooldown_response.additional_properties = d + return suggestions_cooldown_response + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties diff --git a/spec/openapi.json b/spec/openapi.json index 966e3f2..b7de1e9 100644 --- a/spec/openapi.json +++ b/spec/openapi.json @@ -979,10 +979,18 @@ "AiJobSubmitBody": { "type": "object", "properties": { + "attachments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AgenticJobAttachment" + }, + "maxItems": 5, + "description": "Optional image or PDF attachments (e.g. a screenshot or export of a legacy BI dashboard being migrated) giving the AI additional visual context alongside the prompt. Up to 5 files, sharing a combined 50000-token budget with the rest of the prompt." + }, "branchId": { "type": "string", "format": "uuid", - "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId. Use this to query against in-progress model changes.", + "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId. Queries run against the branch model, and if the AI makes model changes (organizations with agentic modeling enabled), they are written to this branch instead of a newly created one. If omitted and the AI makes model changes, a new branch is created automatically.", "example": "550e8400-e29b-41d4-a716-446655440000" }, "conversationId": { @@ -1040,6 +1048,31 @@ "prompt" ] }, + "AgenticJobAttachment": { + "type": "object", + "properties": { + "data": { + "type": "string", + "minLength": 1, + "description": "Base64-encoded file content.", + "example": "iVBORw0KGgoAAAANSUhEUgAA..." + }, + "mimeType": { + "type": "string", + "description": "MIME type of the attachment. Must be an image type (e.g. image/png, image/jpeg) or application/pdf.", + "example": "image/png" + }, + "name": { + "type": "string", + "description": "Optional filename, used for display/logging only.", + "example": "legacy-dashboard-screenshot.png" + } + }, + "required": [ + "data", + "mimeType" + ] + }, "AiJobStatusResponse": { "type": "object", "properties": { @@ -1638,6 +1671,15 @@ "description": "Downgrade threshold, or `null` if the downgrade control is off.", "example": 800 }, + "entityGroupDefaultCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Default per-entity-group AI credit limit, or `null` when embed entity groups are unlimited by default.", + "example": 100 + }, "periodEnd": { "type": "integer", "minimum": 0, @@ -1671,6 +1713,7 @@ "accountCreditLimit", "creditsUsed", "downgradeCredits", + "entityGroupDefaultCredits", "periodEnd", "periodStart", "shutoffCredits", @@ -1689,6 +1732,15 @@ "description": "Credit usage at which AI downgrades to a cheaper model. Omit to leave unchanged, `null` to turn off, or a non-negative number to set. Must be at or below shutoffCredits.", "example": 800 }, + "entityGroupDefaultCredits": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "Default per-entity-group AI credit limit for the billing period — what every embed entity group without an individual limit gets. Omit to leave unchanged, `null` for unlimited by default, or a non-negative number to set.", + "example": 100 + }, "shutoffCredits": { "type": [ "number", @@ -1836,6 +1888,132 @@ ], "additionalProperties": false }, + "AiEntityGroupCreditLimitsResponse": { + "type": "object", + "properties": { + "entityGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "creditLimit": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "The entity group's effective AI credit limit, or `null` for unlimited.", + "example": 50 + }, + "entity": { + "type": "string", + "description": "The embed entity's identifier (the SSO `entity` value).", + "example": "acme-corp" + }, + "usesDefaultLimit": { + "type": "boolean", + "description": "True when the entity group has no individual limit and follows the org default." + } + }, + "required": [ + "creditLimit", + "entity", + "usesDefaultLimit" + ] + } + } + }, + "required": [ + "entityGroups" + ] + }, + "AiEntityGroupCreditLimitsUpdateBody": { + "type": "object", + "properties": { + "entityGroups": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiEntityGroupCreditLimitEntry" + }, + "minItems": 1, + "maxItems": 1000, + "description": "Entity groups to update, at most 1000 per request. Each entry has an `entity` plus exactly one of `creditLimit` (number or `null`) or `useDefaultLimit: true`." + } + }, + "required": [ + "entityGroups" + ], + "additionalProperties": false + }, + "AiEntityGroupCreditLimitEntry": { + "type": "object", + "properties": { + "creditLimit": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "The entity group's individual AI credit limit for the billing period, or `null` for unlimited. Either way this overrides the org default. Mutually exclusive with `useDefaultLimit`.", + "example": 50 + }, + "entity": { + "type": "string", + "description": "The embed entity's identifier (the SSO `entity` value).", + "example": "acme-corp" + }, + "useDefaultLimit": { + "type": "boolean", + "enum": [ + true + ], + "description": "Removes the entity group's individual limit so it follows the org default. Mutually exclusive with `creditLimit`." + } + }, + "required": [ + "entity" + ], + "additionalProperties": false + }, + "AiCreditControlsEntityGroupsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "creditLimit": { + "type": [ + "number", + "null" + ], + "minimum": 0, + "description": "The entity group's individual AI credit limit, or `null` for an explicit unlimited override.", + "example": 50 + }, + "entity": { + "type": "string", + "description": "The embed entity's identifier (the SSO `entity` value).", + "example": "acme-corp" + } + }, + "required": [ + "creditLimit", + "entity" + ] + }, + "description": "Entity groups with an individual AI credit limit, ordered by the entity group id." + } + }, + "required": [ + "pageInfo", + "records" + ] + }, "RoutinesListResponse": { "type": "object", "properties": { @@ -4103,14 +4281,92 @@ "DocumentsGetPermissionsResponse": { "type": "object", "properties": { + "abilities": { + "$ref": "#/components/schemas/DocumentAbilities" + }, "permits": { - "description": "User permits for the document" + "description": "User permits for the document. Present only when userId is provided." } - } + }, + "required": [ + "abilities" + ] + }, + "DocumentAbilities": { + "type": "object", + "properties": { + "canAnalyze": { + "type": "boolean", + "description": "Allow exploring from this document" + }, + "canDownload": { + "type": "boolean", + "description": "Allow downloading" + }, + "canDrill": { + "type": "boolean", + "description": "Allow drill-down" + }, + "canDuplicate": { + "type": "boolean", + "description": "Allow duplicating" + }, + "canRequestAccess": { + "type": "boolean", + "description": "Allow requesting access" + }, + "canSaveSpreadsheets": { + "type": "boolean", + "description": "Allow creating spreadsheets" + }, + "canSchedule": { + "type": "boolean", + "description": "Allow scheduling" + }, + "canUpload": { + "type": "boolean", + "description": "Allow uploads" + }, + "canUseDashboardAi": { + "type": "boolean", + "description": "Allow using dashboard AI" + }, + "canUseTimezoneOverride": { + "type": "boolean", + "description": "Allow timezone override" + }, + "canViewWorkbook": { + "type": "boolean", + "description": "Allow viewing workbook" + }, + "requirePullRequestToPublish": { + "type": "boolean", + "description": "Require pull request to publish changes" + } + }, + "required": [ + "canAnalyze", + "canDownload", + "canDrill", + "canDuplicate", + "canRequestAccess", + "canSaveSpreadsheets", + "canSchedule", + "canUpload", + "canUseDashboardAi", + "canUseTimezoneOverride", + "canViewWorkbook", + "requirePullRequestToPublish" + ], + "description": "Document-level ability values, as stored on the document" }, "DocumentsUpdatePermissionSettingsBody": { "type": "object", "properties": { + "canAnalyze": { + "type": "boolean", + "description": "Allow exploring from this document" + }, "canDownload": { "type": "boolean", "description": "Allow downloading" @@ -4119,6 +4375,18 @@ "type": "boolean", "description": "Allow drill-down" }, + "canDuplicate": { + "type": "boolean", + "description": "Allow duplicating" + }, + "canRequestAccess": { + "type": "boolean", + "description": "Allow requesting access" + }, + "canSaveSpreadsheets": { + "type": "boolean", + "description": "Allow creating spreadsheets" + }, "canSchedule": { "type": "boolean", "description": "Allow scheduling" @@ -12372,6 +12640,16 @@ }, "description": "Optional bookkeeping for this container (e.g. `attachedQueryKey` for auto-placed tiles)" }, + "mobileBehavior": { + "type": "string", + "enum": [ + "stack", + "wrap", + "keep", + "hide" + ], + "description": "Overrides the automatic mobile layout: \"keep\" freezes the desktop grid arrangement, \"hide\" hides the container on mobile (\"stack\" and \"wrap\" apply to row stacks)" + }, "padding": { "anyOf": [ { @@ -20711,6 +20989,16 @@ }, "description": "Optional bookkeeping for this container (e.g. `attachedQueryKey` for auto-placed tiles)" }, + "mobileBehavior": { + "type": "string", + "enum": [ + "stack", + "wrap", + "keep", + "hide" + ], + "description": "Overrides the automatic mobile layout: \"stack\" flips a row to a column, \"wrap\" keeps the row and wraps items, \"keep\" freezes the desktop arrangement, \"hide\" hides the container on mobile" + }, "padding": { "anyOf": [ { @@ -22534,6 +22822,13 @@ "label": { "type": "string" }, + "fieldOrder": { + "type": "string", + "enum": [ + "query", + "control" + ] + }, "options": { "type": "array", "items": { @@ -22980,6 +23275,11 @@ "type": "boolean", "description": "Set by the Kotlin parser when this calc references fields not selected at the top level (AI SQL-gen produces these; UI-authored calcs do not)." }, + "anchor_row": { + "type": "integer", + "exclusiveMinimum": 0, + "description": "The 1-indexed row the Excel-style formula was authored against, so row-relative references resolve to the intended offsets — e.g. a percent-of-previous \"=B4/B5\" authored on row 5. Only used when sql_expression is omitted; defaults to 1 (B1 = this row)." + }, "calc_name": { "type": "string", "description": "Internal identifier for the calculation, used as the column alias." @@ -22998,7 +23298,7 @@ }, "original_formula": { "type": "string", - "description": "The original Excel-style formula before parsing (e.g. \"=SUM(A1:A10)\")." + "description": "The calculation formula. Prefer referencing selected fields by name (e.g. \"=SUM(orders.revenue)\") — name references are stable under column reordering and have no row semantics. Excel-style references also work: column letters map to the query's fields in table order (A = the first field) with rows anchored at row 1 (set anchor_row to author row-relative references against a different row), and calc columns can only be referenced by letter. When sql_expression is omitted, the server parses this formula on write and rejects the request if it does not parse." }, "outside_pivot": { "type": "boolean", @@ -23016,7 +23316,7 @@ "description": "Compiled SQL string produced from the formula." }, "sql_expression": { - "description": "Parsed SQL expression tree (serialized)." + "description": "Parsed SQL expression tree (serialized, server-internal format). Omit it to have the server parse original_formula instead." }, "swallow_errors": { "type": "boolean", @@ -23267,6 +23567,13 @@ "label": { "type": "string" }, + "fieldOrder": { + "type": "string", + "enum": [ + "query", + "control" + ] + }, "options": { "type": "array", "items": { @@ -25635,13 +25942,19 @@ }, "settings": { "$ref": "#/components/schemas/SettingsReadExternal" + }, + "workbookModelId": { + "type": "string", + "format": "uuid", + "description": "Server-assigned WORKBOOK-layer model layered on `modelId`. Read-only — echoed here so a GET round-trips through PATCH; each draft has its own, so a draft read returns the draft workbook’s model." } }, "required": [ "description", "modelId", "name", - "queryPresentations" + "queryPresentations", + "workbookModelId" ] }, "Containers": { @@ -26662,6 +26975,13 @@ "label": { "type": "string" }, + "fieldOrder": { + "type": "string", + "enum": [ + "query", + "control" + ] + }, "options": { "type": "array", "items": { @@ -27066,6 +27386,11 @@ "type": "boolean", "description": "Set by the Kotlin parser when this calc references fields not selected at the top level (AI SQL-gen produces these; UI-authored calcs do not)." }, + "anchor_row": { + "type": "integer", + "exclusiveMinimum": 0, + "description": "The 1-indexed row the Excel-style formula was authored against, so row-relative references resolve to the intended offsets — e.g. a percent-of-previous \"=B4/B5\" authored on row 5. Only used when sql_expression is omitted; defaults to 1 (B1 = this row)." + }, "calc_name": { "type": "string", "description": "Internal identifier for the calculation, used as the column alias." @@ -27084,7 +27409,7 @@ }, "original_formula": { "type": "string", - "description": "The original Excel-style formula before parsing (e.g. \"=SUM(A1:A10)\")." + "description": "The calculation formula. Prefer referencing selected fields by name (e.g. \"=SUM(orders.revenue)\") — name references are stable under column reordering and have no row semantics. Excel-style references also work: column letters map to the query's fields in table order (A = the first field) with rows anchored at row 1 (set anchor_row to author row-relative references against a different row), and calc columns can only be referenced by letter. When sql_expression is omitted, the server parses this formula on write and rejects the request if it does not parse." }, "outside_pivot": { "type": "boolean", @@ -27102,7 +27427,7 @@ "description": "Compiled SQL string produced from the formula." }, "sql_expression": { - "description": "Parsed SQL expression tree (serialized)." + "description": "Parsed SQL expression tree (serialized, server-internal format). Omit it to have the server parse original_formula instead." }, "swallow_errors": { "type": "boolean", @@ -27353,6 +27678,13 @@ "label": { "type": "string" }, + "fieldOrder": { + "type": "string", + "enum": [ + "query", + "control" + ] + }, "options": { "type": "array", "items": { @@ -29800,6 +30132,11 @@ "type": "string", "format": "uuid", "description": "The document's base model. Immutable and accepted only so a GET response round-trips through PATCH: a value matching the current model is a no-op, and a differing value is rejected — it cannot re-base the document. Omit it to leave the model untouched." + }, + "workbookModelId": { + "type": "string", + "format": "uuid", + "description": "The server-assigned workbook-layer model. Read-only and accepted only so a GET response round-trips through PATCH: a value from a GET of the draft or of the published document it targets is a no-op, and any other value is rejected. Omit it otherwise." } }, "additionalProperties": false @@ -30521,6 +30858,11 @@ "description": "The prompt set this run was created from.", "example": "550e8400-e29b-41d4-a716-446655440000" }, + "repeat_count": { + "type": "integer", + "description": "How many times each prompt in the set was executed.", + "example": 1 + }, "run_number": { "type": "integer", "description": "Sequential, per-prompt-set run number.", @@ -30550,6 +30892,7 @@ "is_archived", "model_id", "prompt_set_id", + "repeat_count", "run_number", "stats", "status" @@ -30565,7 +30908,7 @@ }, "total": { "type": "integer", - "description": "Total number of per-prompt jobs in the run.", + "description": "Total number of jobs in the run (prompts × the repeat count).", "example": 12 } }, @@ -30579,7 +30922,7 @@ "properties": { "job_count": { "type": "integer", - "description": "Number of per-prompt agentic jobs created for this run (one per prompt that fanned out successfully). Enqueue onto the work queue happens after creation and is best-effort, so this count reflects jobs created, not necessarily those successfully enqueued.", + "description": "Number of agentic jobs created for this run (one per prompt execution — prompts × repeat count — that fanned out successfully). Enqueue onto the work queue happens after creation and is best-effort, so this count reflects jobs created, not necessarily those successfully enqueued.", "example": 12 }, "run": { @@ -30658,12 +31001,17 @@ "description": "The prompt set this run was created from.", "example": "550e8400-e29b-41d4-a716-446655440000" }, + "repeat_count": { + "type": "integer", + "description": "How many times each prompt in the set was executed. Results carry a `repeat_index` when this is greater than 1.", + "example": 1 + }, "results": { "type": "array", "items": { "$ref": "#/components/schemas/EvalRunResult" }, - "description": "Per-prompt results for this run, ordered by their creation order in the prompt set." + "description": "Per-execution results for this run (one per prompt, times the repeat count). No guaranteed order — group executions by `eval_prompt_id` and order by `repeat_index`." }, "run_number": { "type": "integer", @@ -30691,6 +31039,7 @@ "is_archived", "model_id", "prompt_set_id", + "repeat_count", "results", "run_number", "status" @@ -30727,6 +31076,15 @@ "description": "Failure reason string for prompts whose underlying job failed.", "example": null }, + "eval_prompt_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Snapshot of the prompt id this result was executed for — repeated executions of the same prompt share it, and it survives later prompt deletion. Null on runs created before repeats existed.", + "example": "bb0e8400-e29b-41d4-a716-446655440007" + }, "expectation": { "type": [ "string", @@ -30762,6 +31120,14 @@ "description": "Total wall-clock time (milliseconds) the underlying job spent running warehouse queries — a proxy for query execution time. Null for runs executed before this metric was recorded.", "example": 1800 }, + "repeat_index": { + "type": [ + "integer", + "null" + ], + "description": "0-based repeat number of this execution within the run (see the run's `repeat_count`). Null on runs created before repeats existed.", + "example": 0 + }, "score": { "type": [ "number", @@ -30800,11 +31166,13 @@ "ai_timing_ms", "cost", "error_reason", + "eval_prompt_id", "expectation", "id", "prompt", "query_count", "query_timing_ms", + "repeat_index", "score", "scoring_cost", "timing_ms", @@ -30913,6 +31281,13 @@ "format": "uuid", "description": "Optional branch ID to run against. Must be a branch of the prompt set's model.", "example": "440e8400-e29b-41d4-a716-446655440006" + }, + "repeat_count": { + "type": "integer", + "minimum": 1, + "maximum": 10, + "description": "How many times to execute each prompt in the set (defaults to 1). Between 1 and 10; prompts × repeats may not exceed the per-run job limit.", + "example": 1 } }, "description": "Per-run configuration. Optional — omit if no overrides." @@ -30962,13 +31337,13 @@ "$ref": "#/components/schemas/EvalRunDetail" }, { - "description": "The cancelled run. `status: CANCELLED` and `is_archived: true` after this call." + "description": "The cancelled run. `status: CANCELLED` and `is_archived: false` after this call." } ] }, "total": { "type": "integer", - "description": "Total number of per-prompt jobs in the run.", + "description": "Total number of jobs in the run (prompts × the repeat count).", "example": 12 } }, @@ -31866,6 +32241,167 @@ "value" ] }, + "GenerateSuggestionsResponse": { + "type": "object", + "properties": { + "runId": { + "type": "string", + "format": "uuid", + "description": "The id of the created generation run. Poll `GET /suggestions/runs/{runId}` for status." + }, + "status": { + "type": "string", + "enum": [ + "queued" + ], + "description": "The generation run was enqueued. Generation runs asynchronously." + } + }, + "required": [ + "runId", + "status" + ] + }, + "SuggestionsCooldownResponse": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message." + }, + "lastCompletedAt": { + "type": "string", + "format": "date-time", + "description": "When the most recent run completed." + }, + "retryAfterSeconds": { + "type": "integer", + "description": "Seconds to wait before a new run is allowed." + }, + "status": { + "type": "integer", + "example": 429 + } + }, + "required": [ + "detail", + "lastCompletedAt", + "retryAfterSeconds", + "status" + ] + }, + "SuggestionRun": { + "type": "object", + "properties": { + "completedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "ISO 8601 timestamp when the run reached a terminal state." + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when the run was created (queued)." + }, + "error": { + "type": [ + "object", + "null" + ], + "additionalProperties": {}, + "description": "Failure details when `status` is `failed`; null otherwise." + }, + "executionStartedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "ISO 8601 timestamp when the worker started executing; null while queued." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "The run id." + }, + "status": { + "type": "string", + "enum": [ + "queued", + "executing", + "complete", + "failed" + ], + "description": "Run status. Terminal states are `complete` and `failed`." + }, + "triggerSource": { + "type": "string", + "enum": [ + "manual", + "scheduled" + ], + "description": "Whether the run was triggered manually or by the schedule." + }, + "triggeredBy": { + "type": [ + "object", + "null" + ], + "properties": { + "name": { + "type": [ + "string", + "null" + ] + }, + "userId": { + "type": "string", + "format": "uuid" + } + }, + "required": [ + "name", + "userId" + ], + "description": "The user who triggered a manual run; null for scheduled runs." + } + }, + "required": [ + "completedAt", + "createdAt", + "error", + "executionStartedAt", + "id", + "status", + "triggerSource", + "triggeredBy" + ] + }, + "SuggestionRunLatestResponse": { + "type": "object", + "properties": { + "run": { + "allOf": [ + { + "$ref": "#/components/schemas/SuggestionRun" + }, + { + "type": [ + "object", + "null" + ], + "description": "The most recent run for this model, or null if none exists." + } + ] + } + }, + "required": [ + "run" + ] + }, "ScheduleSuggestionsResponse": { "type": "object", "properties": { @@ -32105,6 +32641,12 @@ "enum": [ "BRANCH" ] + }, + { + "type": "string", + "enum": [ + "QUERY" + ] } ], "default": "SCHEMA", @@ -33087,9 +33629,10 @@ "type": "string", "enum": [ "ssh", - "https_token" + "https_token", + "github_app" ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT. \"github_app\" may appear for connections managed in Omni model settings; it cannot be created or modified through this API.", "example": "ssh" }, "baseBranch": { @@ -33188,9 +33731,10 @@ "type": "string", "enum": [ "ssh", - "https_token" + "https_token", + "github_app" ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT. \"github_app\" may appear for connections managed in Omni model settings; it cannot be created or modified through this API.", "example": "ssh" }, "baseBranch": { @@ -33313,6 +33857,16 @@ "description": "Clone URL of the git repository. SSH (git@...) for deploy key auth, HTTPS (https://...) for token auth.", "example": "git@github.com:org/repo.git" }, + "deployKeyPassphrase": { + "type": "string", + "maxLength": 1024, + "description": "Passphrase for deployPrivateKey when it is encrypted. Omni uses it once to decrypt the key, then stores the key under its own encryption at rest; the passphrase itself is not retained." + }, + "deployPrivateKey": { + "type": "string", + "maxLength": 65536, + "description": "Bring-your-own SSH deploy private key in PEM format (RSA or ED25519, as produced by ssh-keygen), used instead of an Omni-generated keypair. On update it replaces the current key, enabling zero-downtime rotation: authorize the matching public key with your git provider first, then set it here. Only valid for SSH auth." + }, "gitFollower": { "type": "boolean", "default": false, @@ -33376,9 +33930,10 @@ "type": "string", "enum": [ "ssh", - "https_token" + "https_token", + "github_app" ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT. \"github_app\" may appear for connections managed in Omni model settings; it cannot be created or modified through this API.", "example": "ssh" }, "baseBranch": { @@ -33498,6 +34053,16 @@ "description": "Clone URL of the git repository (SSH or HTTPS).", "example": "git@github.com:org/repo.git" }, + "deployKeyPassphrase": { + "type": "string", + "maxLength": 1024, + "description": "Passphrase for deployPrivateKey when it is encrypted. Omni uses it once to decrypt the key, then stores the key under its own encryption at rest; the passphrase itself is not retained." + }, + "deployPrivateKey": { + "type": "string", + "maxLength": 65536, + "description": "Bring-your-own SSH deploy private key in PEM format (RSA or ED25519, as produced by ssh-keygen), used instead of an Omni-generated keypair. On update it replaces the current key, enabling zero-downtime rotation: authorize the matching public key with your git provider first, then set it here. Only valid for SSH auth." + }, "gitFollower": { "type": "boolean", "description": "If true, the shared model will be read-only", @@ -33883,29 +34448,146 @@ "prompt" ] }, - "QueryRunResponse": { + "QueryRunStreamLine": { + "anyOf": [ + { + "$ref": "#/components/schemas/QueryStreamJobsSubmittedLine" + }, + { + "$ref": "#/components/schemas/QueryStreamJobLine" + }, + { + "$ref": "#/components/schemas/QueryStreamFooterLine" + } + ], + "description": "One line of the query/run NDJSON stream: a jobs_submitted header, then one line per job, then a footer." + }, + "QueryStreamJobsSubmittedLine": { "type": "object", "properties": { - "completedQueries": { - "type": "array", - "items": {}, - "description": "Queries that completed synchronously with their results." + "jobs_submitted": { + "type": "object", + "additionalProperties": { + "type": [ + "string", + "null" + ], + "format": "uuid" + }, + "description": "Map of submitted job ID to the client result ID for that job (null when the job has no client result ID). Job IDs are the keys to poll via /api/v1/query/wait." + } + }, + "required": [ + "jobs_submitted" + ], + "description": "First line of the query/run stream: the jobs accepted for execution." + }, + "QueryStreamJobLine": { + "type": "object", + "properties": { + "cache_metadata": { + "description": "Cache metadata for the result (row count, byte size, freshness timestamps, requery plan key)." }, - "jobIds": { + "client_result_id": { + "type": "string", + "description": "Client-supplied result ID echoed back for correlating jobs to queries." + }, + "column_name_mapping": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "error": { + "description": "Structured error details, e.g. an OAuth re-authentication requirement." + }, + "error_message": { + "type": "string", + "description": "Human-readable error message. Present on failed jobs.", + "example": "No such view \"order_items\"" + }, + "error_type": { + "type": "string", + "description": "Machine-readable error category (e.g. PLAN, SQL). Present on failed jobs.", + "example": "PLAN" + }, + "job_id": { + "type": "string", + "description": "ID of the query job this line reports on." + }, + "kill_reason": { + "type": "string", + "description": "Why the job was killed, when it was cancelled." + }, + "query": { + "description": "The query that was executed." + }, + "requery_fallback_sql": { + "type": "string" + }, + "requery_sql": { + "type": "string", + "description": "SQL to re-query the cached result set, when the result supports requery." + }, + "requery_table_name": { + "type": "string" + }, + "result": { + "type": "string", + "description": "Result rows as a base64-encoded Arrow IPC stream. Present on completed jobs. Decode with any Arrow IPC reader and use summary.fields to interpret the columns." + }, + "status": { + "type": "string", + "description": "Job status. Known values include COMPLETE, ERROR, FAILED, and MISSING; new values may be added over time.", + "example": "COMPLETE" + }, + "stream_stats": { + "type": "object", + "additionalProperties": {}, + "description": "Server-side streaming latency stats, in milliseconds." + }, + "summary": { + "description": "Execution summary. summary.fields maps field names to their metadata and is needed to interpret the decoded Arrow table; also carries the generated SQL and cache type." + }, + "used_keys": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "required": [ + "job_id", + "status" + ], + "description": "Per-job line emitted as each job reaches a terminal state. A completed job carries the result set as base64-encoded Arrow IPC in `result`; a failed job carries `error_type` and `error_message` instead." + }, + "QueryStreamFooterLine": { + "type": "object", + "properties": { + "remaining_job_ids": { "type": "array", "items": { "type": "string" }, - "description": "Job IDs for queries running asynchronously. Use /api/v1/query/wait to poll for results.", - "example": [ - "job_abc123", - "job_def456" - ] + "description": "Job IDs that had not completed when the wait window elapsed. Poll /api/v1/query/wait with these IDs until the list is empty.", + "example": [] }, - "plan": { - "description": "Query execution plan (only present if planOnly is true)." + "timed_out": { + "type": "string", + "enum": [ + "false", + "true" + ], + "description": "Whether the wait window elapsed before every job completed. Note: a string (\"true\"/\"false\"), not a boolean.", + "example": "false" } - } + }, + "required": [ + "remaining_job_ids", + "timed_out" + ], + "description": "Last line of the stream." }, "QueryTimeoutResponse": { "type": "object", @@ -33991,18 +34673,16 @@ } } }, - "QueryWaitResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": {}, - "description": "Array of completed query results. Each result contains the query data or an error." + "QueryWaitStreamLine": { + "anyOf": [ + { + "$ref": "#/components/schemas/QueryStreamJobLine" + }, + { + "$ref": "#/components/schemas/QueryStreamFooterLine" } - }, - "required": [ - "results" - ] + ], + "description": "One line of the query/wait NDJSON stream: one line per completed job, then a footer. Unlike query/run, there is no jobs_submitted header line." }, "SchedulesListItem": { "type": "object", @@ -36422,7 +37102,7 @@ "paths": { "/api/v1/ai/generate-query": { "post": { - "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model.", + "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model. The effective user's per-connector AI toggles (set in the chat + menu) govern which integration tools the agent may use.", "operationId": "aiGenerateQuery", "summary": "Generate query from natural language", "tags": [ @@ -36647,7 +37327,7 @@ }, "/api/v1/ai/jobs": { "post": { - "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId.", + "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId. The effective user's per-connector AI toggles (set in the chat + menu) govern which integration tools the agent may use.", "operationId": "aiJobSubmit", "summary": "Submit an AI job", "tags": [ @@ -37252,7 +37932,7 @@ }, "/api/v1/ai/credit-controls": { "get": { - "description": "Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per-user credit limit, plus read-only context (the credit limit, usage so far this billing period, and the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same AI-admin permission.", + "description": "Get the organization's AI credit controls: the downgrade and shutoff thresholds, the default per-user and per-entity-group credit limits, plus read-only context (the credit limit, usage so far this billing period, and the period bounds). This is the API mirror of the AI Hub credit controls page and requires the same AI-admin permission.", "operationId": "aiCreditControlsGet", "summary": "Get AI credit controls", "tags": [ @@ -37292,7 +37972,7 @@ } }, "patch": { - "description": "Update the organization's AI credit controls: the downgrade and shutoff thresholds and the default per-user credit limit (userDefaultCredits). All fields are optional and tri-state: omit a field to leave it unchanged, send `null` to turn that control off (for userDefaultCredits: unlimited by default), or send a non-negative number to set it. At least one field is required. The `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the full current state, the same shape as GET.", + "description": "Update the organization's AI credit controls: the downgrade and shutoff thresholds, the default per-user credit limit (userDefaultCredits), and the default per-entity-group credit limit (entityGroupDefaultCredits). All fields are optional and tri-state: omit a field to leave it unchanged, send `null` to turn that control off (for the defaults: unlimited by default), or send a non-negative number to set it. At least one field is required. The `downgradeCredits <= shutoffCredits` invariant is enforced against the merged result. Returns the full current state, the same shape as GET.", "operationId": "aiCreditControlsUpdate", "summary": "Update AI credit controls", "tags": [ @@ -37389,11 +38069,230 @@ ], "responses": { "200": { - "description": "One page of users' individual AI credit limits.", + "description": "One page of users' individual AI credit limits.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditControlsUsersListResponse" + } + } + } + }, + "400": { + "description": "Invalid cursor or pageSize.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions, or per-user AI credit limits are not enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + }, + "patch": { + "description": "Set individual users' AI credit limits in bulk. Each entry names a user (`userId`) and either sets an individual limit (`creditLimit`: a non-negative number, or `null` for unlimited) or removes one (`useDefaultLimit: true`) so the user follows the org default. Each userId may appear at most once and must be a member of the organization. All updates are applied in one transaction, so either every entry takes effect or none do — an invalid userId fails the whole request with a 404 naming it. Requires the same manage-user-attributes permission as the AI credit limit settings pages.", + "operationId": "aiCreditControlsUsersUpdate", + "summary": "Set individual users' AI credit limits", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiUserCreditLimitsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "All entries applied. Returns each user's effective limit, in request order.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiUserCreditLimitsResponse" + } + } + } + }, + "400": { + "description": "Invalid request. Common causes: an empty users array, more than 1000 entries, an entry with both creditLimit and useDefaultLimit (or neither), a negative creditLimit, or a duplicated userId.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions, per-user AI credit limits are not enabled, or credit controls editing is disabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "A userId is not a member of the organization; the response names the first invalid id. No limits are changed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/credit-controls/entity-groups": { + "patch": { + "description": "Set individual embed entity groups' AI credit limits in bulk. Each entry names an entity group by its embed `entity` string and either sets an individual limit (`creditLimit`: a non-negative number, or `null` for unlimited) or removes one (`useDefaultLimit: true`) so the entity group follows the org default. Each entity may appear at most once and must have an entity group in the organization. All updates are applied in one transaction, so either every entry takes effect or none do — an unknown entity fails the whole request with a 404 naming it. Requires the same add/remove-users permission as the group settings page and the embed-entity credit-limit feature flag.", + "operationId": "aiCreditControlsEntityGroupsUpdate", + "summary": "Set individual entity groups' AI credit limits", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiEntityGroupCreditLimitsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "All entries applied. Returns each entity group's effective limit, in request order.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiEntityGroupCreditLimitsResponse" + } + } + } + }, + "400": { + "description": "Invalid request. Common causes: an empty entityGroups array, more than 1000 entries, an entry with both creditLimit and useDefaultLimit (or neither), a negative creditLimit, or a duplicated entity.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions, per-entity-group AI credit limits are not enabled, or credit controls editing is disabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "An entity has no entity group in the organization; the response names the first invalid entity. No limits are changed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + }, + "get": { + "description": "List the organization's active individual embed entity-group AI credit limits, keyed by the embed `entity` string. Only entity groups with an individual limit appear — everyone else follows the org default. A `null` creditLimit is an explicit unlimited override, distinct from following the default. Paginated via opaque cursors: pass `pageInfo.nextCursor` from one response as the `cursor` query parameter on the next request. Requires the same add/remove-users permission as the PATCH.", + "operationId": "aiCreditControlsEntityGroupsList", + "summary": "List individual entity groups' AI credit limits", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + } + ], + "responses": { + "200": { + "description": "One page of entity groups' individual AI credit limits.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiCreditControlsUsersListResponse" + "$ref": "#/components/schemas/AiCreditControlsEntityGroupsListResponse" } } } @@ -37419,7 +38318,7 @@ } }, "403": { - "description": "Insufficient permissions, or per-user AI credit limits are not enabled for the organization.", + "description": "Insufficient permissions, or per-entity-group AI credit limits are not enabled for the organization.", "content": { "application/json": { "schema": { @@ -37429,76 +38328,6 @@ } } } - }, - "patch": { - "description": "Set individual users' AI credit limits in bulk. Each entry names a user (`userId`) and either sets an individual limit (`creditLimit`: a non-negative number, or `null` for unlimited) or removes one (`useDefaultLimit: true`) so the user follows the org default. Each userId may appear at most once and must be a member of the organization. All updates are applied in one transaction, so either every entry takes effect or none do — an invalid userId fails the whole request with a 404 naming it. Requires the same manage-user-attributes permission as the AI credit limit settings pages.", - "operationId": "aiCreditControlsUsersUpdate", - "summary": "Set individual users' AI credit limits", - "tags": [ - "AI" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiUserCreditLimitsUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "All entries applied. Returns each user's effective limit, in request order.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiUserCreditLimitsResponse" - } - } - } - }, - "400": { - "description": "Invalid request. Common causes: an empty users array, more than 1000 entries, an entry with both creditLimit and useDefaultLimit (or neither), a negative creditLimit, or a duplicated userId.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "Insufficient permissions, per-user AI credit limits are not enabled, or credit controls editing is disabled for the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "A userId is not a member of the organization; the response names the first invalid id. No limits are changed.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - } - } } }, "/api/v1/ai/routines": { @@ -37986,7 +38815,7 @@ }, "/api/v1/ai/routines/{id}/trigger": { "post": { - "description": "Run a routine immediately, in addition to its schedule. The run executes once using the routine owner's permissions and delivers the AI response to every configured recipient — it is not a private preview. Returns once the run has started; the result is delivered asynchronously. Organization API keys can pass `?userId=` to act on behalf of a specific organization member.", + "description": "Run a routine immediately, in addition to its schedule. The run executes once using the routine owner's permissions and delivers the AI response to every configured recipient — it is not a private preview. Because runs execute as the owner, the owner's per-connector AI toggles (set in the chat + menu) govern which integration tools the agent may use. Returns once the run has started; the result is delivered asynchronously. Organization API keys can pass `?userId=` to act on behalf of a specific organization member.", "operationId": "routineTrigger", "summary": "Run a routine now", "tags": [ @@ -41789,6 +42618,7 @@ }, "/api/v1/documents/{identifier}/permissions": { "get": { + "description": "Returns the document-level ability values (the Share dialog \"Abilities\" toggles), plus the resolved permits for a specific user when `userId` is provided.", "operationId": "documentsGetPermissions", "summary": "Get document permissions", "tags": [ @@ -41810,17 +42640,17 @@ "schema": { "type": "string", "format": "uuid", - "description": "User membership ID to check permissions for" + "description": "User membership ID to check permissions for. When omitted, only the document-level abilities are returned." }, - "required": true, - "description": "User membership ID to check permissions for", + "required": false, + "description": "User membership ID to check permissions for. When omitted, only the document-level abilities are returned.", "name": "userId", "in": "query" } ], "responses": { "200": { - "description": "User permissions for the document", + "description": "Document abilities, plus user permits when userId is provided", "content": { "application/json": { "schema": { @@ -43030,7 +43860,7 @@ } }, "400": { - "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded, or a `modelId` that differs from the document’s immutable base model)." + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded, a `modelId` that differs from the document’s immutable base model, or a `workbookModelId` that differs from the read-only value a GET returns)." }, "401": { "description": "Authentication required." @@ -43065,11 +43895,11 @@ { "schema": { "type": "string", - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "description": "Draft workbook identifier (see `PATCH /api/v2/documents/{identifier}/draft`).", "example": "def456" }, "required": true, - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "description": "Draft workbook identifier (see `PATCH /api/v2/documents/{identifier}/draft`).", "name": "draftIdentifier", "in": "path" }, @@ -43137,11 +43967,11 @@ { "schema": { "type": "string", - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "description": "Draft workbook identifier (see `PATCH /api/v2/documents/{identifier}/draft`).", "example": "def456" }, "required": true, - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "description": "Draft workbook identifier (see `PATCH /api/v2/documents/{identifier}/draft`).", "name": "draftIdentifier", "in": "path" }, @@ -43178,7 +44008,7 @@ } }, "400": { - "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded, or a `modelId` that differs from the document’s immutable base model)." + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded, a `modelId` that differs from the document’s immutable base model, or a `workbookModelId` that differs from the read-only value a GET returns)." }, "401": { "description": "Authentication required." @@ -43201,6 +44031,70 @@ } } }, + "/api/v2/documents/{identifier}/draft/{draftIdentifier}/dashboard": { + "delete": { + "description": "Remove the dashboard from an existing draft, leaving a workbook-only document. Its schedules are removed too, but at publish time (see below), not on this call. Parity with the UI’s \"Remove dashboard\" action, and the inverse of adding a dashboard via a `containers` patch.\n\nOperates only on the draft named by `draftIdentifier`, which the caller creates first via `PATCH …/draft`. Requiring an explicit draft keeps the removal from silently reusing (and clobbering) a draft that holds other unpublished work.\n\nNo auto-publish — publish via `POST …/draft/publish` to make the document workbook-only (publishing also clears the previously-published dashboard’s schedules). Idempotent: a draft that is already workbook-only returns 200 unchanged.", + "operationId": "documentsV2RemoveDashboard", + "summary": "Remove dashboard from document", + "tags": [ + "Documents" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Draft workbook identifier (see `PATCH /api/v2/documents/{identifier}/draft`).", + "example": "def456" + }, + "required": true, + "description": "Draft workbook identifier (see `PATCH /api/v2/documents/{identifier}/draft`).", + "name": "draftIdentifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Published document identifier.", + "example": "abc123" + }, + "required": true, + "description": "Published document identifier.", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Dashboard removed on the draft (or a no-op when already workbook-only); the response carries the `draftIdentifier`.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" + } + } + } + }, + "401": { + "description": "Authentication required." + }, + "403": { + "description": "Insufficient permissions to update the document." + }, + "404": { + "description": "Document or draft not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document." + }, + "422": { + "description": "The document is an app, not a dashboard." + } + } + } + }, "/api/v2/documents/{identifier}/draft/publish": { "post": { "description": "Publish the document's current main (non-branch) draft, promoting it to the published version. No request body — the draft is consumed, so the response echoes the now-published document metadata.\n\nOnly the main draft is publishable here; a branch-attached draft is published by merging its branch (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft returns 404. Documents that require a pull request to publish return 400.", @@ -43940,7 +44834,7 @@ } }, "post": { - "description": "Create and start a new run against an existing prompt set. The run enqueues one agentic job per prompt and begins executing immediately. Returns the newly created run with its initial per-prompt result rows.", + "description": "Create and start a new run against an existing prompt set. The run enqueues `run_config.repeat_count` agentic jobs per prompt (default 1) and begins executing immediately. Returns the newly created run with its initial per-execution result rows.", "operationId": "aiEvalRunsCreate", "summary": "Start an eval run", "tags": [ @@ -44008,7 +44902,7 @@ } }, "422": { - "description": "`run_config.branch_id` does not belong to the prompt set's model.", + "description": "`run_config.branch_id` does not belong to the prompt set's model, or prompts × `run_config.repeat_count` exceeds the per-run job limit.", "content": { "application/json": { "schema": { @@ -45179,6 +46073,181 @@ } } }, + "/api/v1/models/{modelId}/suggestions/generate": { + "post": { + "description": "Triggers an AI suggestion generation run for the shared model and enqueues the async job. Poll `GET /suggestions/runs/{runId}` for status. Requires organization admin permissions. At most one active run per model; a cooldown applies after a completed run.", + "operationId": "modelSuggestionsGenerate", + "summary": "Generate model suggestions", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestions belong to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestions belong to", + "name": "modelId", + "in": "path" + } + ], + "responses": { + "202": { + "description": "Generation run enqueued", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenerateSuggestionsResponse" + } + } + } + }, + "400": { + "description": "Malformed `modelId`" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Model not found in this organization" + }, + "405": { + "description": "Method not allowed" + }, + "409": { + "description": "A generation run is already active for this model" + }, + "429": { + "description": "A run completed recently; retry after the cooldown (see the `Retry-After` header)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuggestionsCooldownResponse" + } + } + } + }, + "500": { + "description": "Failed to enqueue the generation job" + } + } + } + }, + "/api/v1/models/{modelId}/suggestions/runs/{runId}": { + "get": { + "description": "Returns the status of a specific generation run. Poll until `status` is terminal (`complete` or `failed`), then re-fetch the suggestions list. Requires organization admin permissions.", + "operationId": "modelSuggestionsRunGet", + "summary": "Get a generation run", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the run belongs to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the run belongs to", + "name": "modelId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the generation run", + "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" + }, + "required": true, + "description": "UUID of the generation run", + "name": "runId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The generation run", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuggestionRun" + } + } + } + }, + "400": { + "description": "Malformed id" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Run not found in this organization/model" + } + } + } + }, + "/api/v1/models/{modelId}/suggestions/runs/latest": { + "get": { + "description": "Returns the most recent generation run for the shared model (the active run if one is in flight, otherwise the last terminal run), or null if none exists. Requires organization admin permissions.", + "operationId": "modelSuggestionsRunLatest", + "summary": "Get the latest generation run", + "tags": [ + "AI Model Suggestions" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "UUID of the shared model the suggestions belong to", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "UUID of the shared model the suggestions belong to", + "name": "modelId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The latest generation run, or null", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuggestionRunLatestResponse" + } + } + } + }, + "400": { + "description": "Malformed `modelId`" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Feature not enabled, AI disabled, model is not a shared model, or caller lacks organization admin permissions" + }, + "404": { + "description": "Model not found in this organization" + } + } + } + }, "/api/v1/models/{modelId}/suggestions/schedule": { "put": { "description": "Enables the daily schedule that generates suggestions for the shared model. Idempotent — re-enabling leaves an existing schedule untouched. Requires organization admin permissions.", @@ -45659,7 +46728,7 @@ } }, "post": { - "description": "Create a new model. Supports creating schema, shared, branch, and shared_extension models.", + "description": "Create a new model. Supports creating schema, shared, branch, shared_extension, and query models. A query model (modelKind QUERY) is created empty under a workbook model (baseModelId); populate its views and fields via the model YAML endpoint.", "operationId": "modelsCreate", "summary": "Create model", "tags": [ @@ -47401,6 +48470,7 @@ } }, "post": { + "description": "Create git configuration for a model. For SSH auth, Omni generates a deploy keypair by default; supply deployPrivateKey (with deployKeyPassphrase for encrypted keys) to bring your own instead.", "operationId": "modelsGitCreate", "summary": "Create git configuration", "tags": [ @@ -47458,6 +48528,7 @@ } }, "patch": { + "description": "Update git configuration for a model. Only provided fields are changed. For SSH auth, a bring-your-own deploy key can be set via deployPrivateKey (with deployKeyPassphrase for encrypted keys), enabling zero-downtime key rotation: authorize the matching public key with the git provider first, then set the key here.", "operationId": "modelsGitUpdate", "summary": "Update git configuration", "tags": [ @@ -48142,6 +49213,7 @@ }, "/api/v1/query/run": { "post": { + "description": "Runs a semantic query. By default (no `resultType`) the response is a stream of newline-delimited JSON (`Content-Type: text/ndjson`), one JSON object per line: a `jobs_submitted` header, then one line per job as it reaches a terminal state (a completed job carries the result set as base64-encoded Arrow IPC in `result`; use `summary.fields` to interpret the decoded columns), then a footer. A footer with non-empty `remaining_job_ids` means the wait window elapsed before every job finished — poll GET /api/v1/query/wait with those IDs until the list is empty. When `resultType` is set, the response is instead a single CSV, XLSX, or JSON document, and a timeout is reported as a 408.", "operationId": "queryRun", "summary": "Execute a semantic query", "tags": [ @@ -48171,11 +49243,34 @@ }, "responses": { "200": { - "description": "Query executed or started successfully", + "description": "Query executed or started successfully. The default response (no resultType) is a text/ndjson stream — one JSON object per line, each matching QueryRunStreamLine; it cannot be parsed as a single JSON document. When resultType is set, the body is a single CSV, XLSX, or JSON document instead.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/QueryRunResponse" + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Array of result-row objects keyed by field name. Returned only when resultType is \"json\"." + } + }, + "application/vnd.ms-excel": { + "schema": { + "description": "XLSX document. Returned only when resultType is \"xlsx\".", + "format": "binary", + "type": "string" + } + }, + "text/csv": { + "schema": { + "description": "CSV document. Returned only when resultType is \"csv\".", + "type": "string" + } + }, + "text/ndjson": { + "schema": { + "$ref": "#/components/schemas/QueryRunStreamLine" } } } @@ -48193,7 +49288,7 @@ "description": "Model, topic, view, or branch not found" }, "408": { - "description": "Query timed out. The response includes remaining_job_ids that can be polled via the query/wait endpoint.", + "description": "Query timed out. Only returned when resultType is set — the default text/ndjson response reports timeouts in-band via the footer line's remaining_job_ids instead. The response includes remaining_job_ids that can be polled via the query/wait endpoint.", "content": { "application/json": { "schema": { @@ -48210,6 +49305,7 @@ }, "/api/v1/query/wait": { "get": { + "description": "Waits for previously submitted query jobs and streams results as they complete. The response is a stream of newline-delimited JSON (`Content-Type: text/ndjson`): one line per job (same shape as the job lines from query/run, including the base64-encoded Arrow IPC `result`), then a footer. Unlike query/run, there is no `jobs_submitted` header line. If the footer's `remaining_job_ids` is non-empty, call this endpoint again with those IDs until it is empty.", "operationId": "queryWait", "summary": "Wait for query jobs to complete", "tags": [ @@ -48230,11 +49326,11 @@ ], "responses": { "200": { - "description": "Query results for completed jobs", + "description": "Query results for completed jobs, as a text/ndjson stream — one JSON object per line, each matching QueryWaitStreamLine; it cannot be parsed as a single JSON document.", "content": { - "application/json": { + "text/ndjson": { "schema": { - "$ref": "#/components/schemas/QueryWaitResponse" + "$ref": "#/components/schemas/QueryWaitStreamLine" } } } diff --git a/spec/provenance.json b/spec/provenance.json index 79313e2..7bcdc0a 100644 --- a/spec/provenance.json +++ b/spec/provenance.json @@ -1,5 +1,5 @@ { - "source": "omni repo @ 7805fc5e5dcc6bcd3fbc39885b5f675fa8470195", - "spec_sha256": "8777d18dde709fbf3c1691141774fbc8cc1baba24d8a1ccd8487717322547c48", - "synced_at": "2026-07-16T19:52:43Z" + "source": "omni repo @ c3fe7934808a8086999643252e5c19d0917ed171", + "spec_sha256": "5d3668f9d79b29e5326c5540afa4cead163f52a4613504ca262f87912fab2bbf", + "synced_at": "2026-07-22T18:58:19Z" } \ No newline at end of file