From c3d98fc06416eabe61dc151f9f92fb0bfb3595e9 Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Thu, 29 May 2025 10:19:56 +0530 Subject: [PATCH 01/16] chore: Move URL comparison logic to utils (#11617) --- app/javascript/portal/portalHelpers.js | 47 +------------------------- package.json | 2 +- pnpm-lock.yaml | 10 +++--- 3 files changed, 7 insertions(+), 52 deletions(-) diff --git a/app/javascript/portal/portalHelpers.js b/app/javascript/portal/portalHelpers.js index 68e2cb6a8..bed50387e 100644 --- a/app/javascript/portal/portalHelpers.js +++ b/app/javascript/portal/portalHelpers.js @@ -2,6 +2,7 @@ import { createApp } from 'vue'; import VueDOMPurifyHTML from 'vue-dompurify-html'; import { domPurifyConfig } from '../shared/helpers/HTMLSanitizer'; import { directive as onClickaway } from 'vue3-click-away'; +import { isSameHost } from '@chatwoot/utils'; import slugifyWithCounter from '@sindresorhus/slugify'; import PublicArticleSearch from './components/PublicArticleSearch.vue'; @@ -25,52 +26,6 @@ export const getHeadingsfromTheArticle = () => { return rows; }; -/** - * Converts various input formats to URL objects. - * Handles URL objects, domain strings, relative paths, and full URLs. - * @param {string|URL} input - Input to convert to URL object - * @returns {URL|null} URL object or null if input is invalid - */ -const toURL = input => { - if (!input) return null; - if (input instanceof URL) return input; - - if ( - typeof input === 'string' && - !input.includes('://') && - !input.startsWith('/') - ) { - return new URL(`https://${input}`); - } - - if (typeof input === 'string' && input.startsWith('/')) { - return new URL(input, window.location.origin); - } - - return new URL(input); -}; - -/** - * Determines if two URLs belong to the same host by comparing their normalized URL objects. - * Handles various input formats including URL objects, domain strings, relative paths, and full URLs. - * Returns false if either URL cannot be parsed or normalized. - * @param {string|URL} url1 - First URL to compare - * @param {string|URL} url2 - Second URL to compare - * @returns {boolean} True if both URLs have the same host, false otherwise - */ -const isSameHost = (url1, url2) => { - try { - const urlObj1 = toURL(url1); - const urlObj2 = toURL(url2); - - if (!urlObj1 || !urlObj2) return false; - - return urlObj1.hostname === urlObj2.hostname; - } catch (error) { - return false; - } -}; - export const openExternalLinksInNewTab = () => { const { customDomain, hostURL } = window.portalConfig; const isOnArticlePage = diff --git a/package.json b/package.json index 90b7708f6..6280ec7fd 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@breezystack/lamejs": "^1.2.7", "@chatwoot/ninja-keys": "1.2.3", "@chatwoot/prosemirror-schema": "1.1.1-next", - "@chatwoot/utils": "^0.0.43", + "@chatwoot/utils": "^0.0.45", "@formkit/core": "^1.6.7", "@formkit/vue": "^1.6.7", "@hcaptcha/vue3-hcaptcha": "^1.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index af7703fc6..606ebbb63 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,8 +23,8 @@ importers: specifier: 1.1.1-next version: 1.1.1-next '@chatwoot/utils': - specifier: ^0.0.43 - version: 0.0.43 + specifier: ^0.0.45 + version: 0.0.45 '@formkit/core': specifier: ^1.6.7 version: 1.6.7 @@ -406,8 +406,8 @@ packages: '@chatwoot/prosemirror-schema@1.1.1-next': resolution: {integrity: sha512-/M2qZ+ZF7GlQNt1riwVP499fvp3hxSqd5iy8hxyF9pkj9qQ+OKYn5JK+v3qwwqQY3IxhmNOn1Lp6tm7vstrd9Q==} - '@chatwoot/utils@0.0.43': - resolution: {integrity: sha512-kMIXAGebCak9qOi68QnGer+rQLLo/z2N9cR+7tvGdZCW0ThDiVCF7JbHYHVDlYsdDFIx0FLlyIdCfEbooVT2Dw==} + '@chatwoot/utils@0.0.45': + resolution: {integrity: sha512-zqmuri6MrEFAY1tLv7Z3HBy4Ig60LhSrLkEiHegVsOVSxPv4Bedq+xmAW7LphvcLNgbkkvu17MU91gvMVlpEHw==} engines: {node: '>=10'} '@codemirror/commands@6.7.0': @@ -5255,7 +5255,7 @@ snapshots: prosemirror-utils: 1.2.2(prosemirror-model@1.22.3)(prosemirror-state@1.4.3) prosemirror-view: 1.34.1 - '@chatwoot/utils@0.0.43': + '@chatwoot/utils@0.0.45': dependencies: date-fns: 2.30.0 From f6510e0d4367f5a7a9e9a142032483063be34358 Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Thu, 29 May 2025 11:23:27 +0530 Subject: [PATCH 02/16] docs: add swagger spec for accounts API (#11620) --- swagger/definitions/index.yml | 7 + .../request/account/update_payload.yml | 49 +++ .../definitions/resource/account_detail.yml | 84 +++++ .../resource/account_show_response.yml | 13 + swagger/paths/application/accounts/show.yml | 28 ++ swagger/paths/application/accounts/update.yml | 43 +++ swagger/paths/index.yml | 9 + swagger/swagger.json | 331 ++++++++++++++++++ swagger/tag_groups/application_swagger.json | 199 +++++++++++ swagger/tag_groups/client_swagger.json | 199 +++++++++++ swagger/tag_groups/other_swagger.json | 199 +++++++++++ swagger/tag_groups/platform_swagger.json | 199 +++++++++++ 12 files changed, 1360 insertions(+) create mode 100644 swagger/definitions/request/account/update_payload.yml create mode 100644 swagger/definitions/resource/account_detail.yml create mode 100644 swagger/definitions/resource/account_show_response.yml create mode 100644 swagger/paths/application/accounts/show.yml create mode 100644 swagger/paths/application/accounts/update.yml diff --git a/swagger/definitions/index.yml b/swagger/definitions/index.yml index 57e10e2dd..faf947217 100644 --- a/swagger/definitions/index.yml +++ b/swagger/definitions/index.yml @@ -60,6 +60,10 @@ webhook: $ref: ./resource/webhook.yml account: $ref: ./resource/account.yml +account_detail: + $ref: ./resource/account_detail.yml +account_show_response: + $ref: ./resource/account_show_response.yml account_user: $ref: ./resource/account_user.yml platform_account: @@ -87,6 +91,9 @@ public_inbox: account_create_update_payload: $ref: ./request/account/create_update_payload.yml +account_update_payload: + $ref: ./request/account/update_payload.yml + account_user_create_update_payload: $ref: ./request/account_user/create_update_payload.yml diff --git a/swagger/definitions/request/account/update_payload.yml b/swagger/definitions/request/account/update_payload.yml new file mode 100644 index 000000000..b2e47cbc2 --- /dev/null +++ b/swagger/definitions/request/account/update_payload.yml @@ -0,0 +1,49 @@ +type: object +properties: + name: + type: string + description: Name of the account + example: 'My Account' + locale: + type: string + description: The locale of the account + example: 'en' + domain: + type: string + description: The domain of the account + example: 'example.com' + support_email: + type: string + description: The support email of the account + example: 'support@example.com' + # Settings parameters (stored in settings JSONB column) + auto_resolve_after: + type: integer + minimum: 10 + maximum: 1439856 + nullable: true + description: Auto resolve conversations after specified minutes + example: 1440 + auto_resolve_message: + type: string + nullable: true + description: Message to send when auto resolving + example: "This conversation has been automatically resolved due to inactivity" + auto_resolve_ignore_waiting: + type: boolean + nullable: true + description: Whether to ignore waiting conversations for auto resolve + example: false + # Custom attributes parameters (stored in custom_attributes JSONB column) + industry: + type: string + description: Industry type + example: "Technology" + company_size: + type: string + description: Company size + example: "50-100" + timezone: + type: string + description: Account timezone + example: "UTC" \ No newline at end of file diff --git a/swagger/definitions/resource/account_detail.yml b/swagger/definitions/resource/account_detail.yml new file mode 100644 index 000000000..0ff463bae --- /dev/null +++ b/swagger/definitions/resource/account_detail.yml @@ -0,0 +1,84 @@ +type: object +properties: + id: + type: number + description: Account ID + name: + type: string + description: Name of the account + locale: + type: string + description: The locale of the account + domain: + type: string + description: The domain of the account + support_email: + type: string + description: The support email of the account + status: + type: string + description: The status of the account + created_at: + type: string + format: date-time + description: The creation date of the account + cache_keys: + type: object + description: Cache keys for the account + features: + type: array + items: + type: string + description: Enabled features for the account + settings: + type: object + description: Account settings + properties: + auto_resolve_after: + type: number + description: Auto resolve conversations after specified minutes + auto_resolve_message: + type: string + description: Message to send when auto resolving + auto_resolve_ignore_waiting: + type: boolean + description: Whether to ignore waiting conversations for auto resolve + custom_attributes: + type: object + description: Custom attributes of the account + properties: + plan_name: + type: string + description: Subscription plan name + subscribed_quantity: + type: number + description: Subscribed quantity + subscription_status: + type: string + description: Subscription status + subscription_ends_on: + type: string + format: date + description: Subscription end date + industry: + type: string + description: Industry type + company_size: + type: string + description: Company size + timezone: + type: string + description: Account timezone + logo: + type: string + description: Account logo URL + onboarding_step: + type: string + description: Current onboarding step + marked_for_deletion_at: + type: string + format: date-time + description: When account was marked for deletion + marked_for_deletion_reason: + type: string + description: Reason for account deletion \ No newline at end of file diff --git a/swagger/definitions/resource/account_show_response.yml b/swagger/definitions/resource/account_show_response.yml new file mode 100644 index 000000000..208b27218 --- /dev/null +++ b/swagger/definitions/resource/account_show_response.yml @@ -0,0 +1,13 @@ +allOf: + - $ref: '#/components/schemas/account_detail' + - type: object + properties: + latest_chatwoot_version: + type: string + description: Latest version of Chatwoot available + example: "3.0.0" + subscribed_features: + type: array + items: + type: string + description: List of subscribed enterprise features (if enterprise edition is enabled) \ No newline at end of file diff --git a/swagger/paths/application/accounts/show.yml b/swagger/paths/application/accounts/show.yml new file mode 100644 index 000000000..56e0c8052 --- /dev/null +++ b/swagger/paths/application/accounts/show.yml @@ -0,0 +1,28 @@ +tags: + - Account +operationId: get-account-details +summary: Get account details +description: Get the details of the current account +security: + - userApiKey: [] +parameters: + - $ref: '#/components/parameters/account_id' +responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/account_show_response' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/bad_request_error' + '404': + description: Account not found + content: + application/json: + schema: + $ref: '#/components/schemas/bad_request_error' \ No newline at end of file diff --git a/swagger/paths/application/accounts/update.yml b/swagger/paths/application/accounts/update.yml new file mode 100644 index 000000000..23c9c40f8 --- /dev/null +++ b/swagger/paths/application/accounts/update.yml @@ -0,0 +1,43 @@ +tags: + - Account +operationId: update-account +summary: Update account +description: Update account details, settings, and custom attributes +security: + - userApiKey: [] +parameters: + - $ref: '#/components/parameters/account_id' +requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/account_update_payload' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/account_update_payload' +responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/account_detail' + '401': + description: Unauthorized (requires administrator role) + content: + application/json: + schema: + $ref: '#/components/schemas/bad_request_error' + '404': + description: Account not found + content: + application/json: + schema: + $ref: '#/components/schemas/bad_request_error' + '422': + description: Validation error + content: + application/json: + schema: + $ref: '#/components/schemas/bad_request_error' \ No newline at end of file diff --git a/swagger/paths/index.yml b/swagger/paths/index.yml index 379b2eef0..a70800b89 100644 --- a/swagger/paths/index.yml +++ b/swagger/paths/index.yml @@ -166,6 +166,15 @@ # ------------ Application API routes ------------# +# Accounts +/api/v1/accounts/{id}: + parameters: + - $ref: '#/components/parameters/account_id' + get: + $ref: ./application/accounts/show.yml + patch: + $ref: ./application/accounts/update.yml + # AgentBots /api/v1/accounts/{account_id}/agent_bots: parameters: diff --git a/swagger/swagger.json b/swagger/swagger.json index 943b7a3e8..b9ecbcf27 100644 --- a/swagger/swagger.json +++ b/swagger/swagger.json @@ -1476,6 +1476,138 @@ } } }, + "/api/v1/accounts/{id}": { + "parameters": [ + { + "$ref": "#/components/parameters/account_id" + } + ], + "get": { + "tags": [ + "Account" + ], + "operationId": "get-account-details", + "summary": "Get account details", + "description": "Get the details of the current account", + "security": [ + { + "userApiKey": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/account_id" + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/account_show_response" + } + } + } + }, + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/bad_request_error" + } + } + } + }, + "404": { + "description": "Account not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/bad_request_error" + } + } + } + } + } + }, + "patch": { + "tags": [ + "Account" + ], + "operationId": "update-account", + "summary": "Update account", + "description": "Update account details, settings, and custom attributes", + "security": [ + { + "userApiKey": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/account_id" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/account_update_payload" + } + }, + "application/x-www-form-urlencoded": { + "schema": { + "$ref": "#/components/schemas/account_update_payload" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/account_detail" + } + } + } + }, + "401": { + "description": "Unauthorized (requires administrator role)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/bad_request_error" + } + } + } + }, + "404": { + "description": "Account not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/bad_request_error" + } + } + } + }, + "422": { + "description": "Validation error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/bad_request_error" + } + } + } + } + } + } + }, "/api/v1/accounts/{account_id}/agent_bots": { "parameters": [ { @@ -8774,6 +8906,145 @@ } } }, + "account_detail": { + "type": "object", + "properties": { + "id": { + "type": "number", + "description": "Account ID" + }, + "name": { + "type": "string", + "description": "Name of the account" + }, + "locale": { + "type": "string", + "description": "The locale of the account" + }, + "domain": { + "type": "string", + "description": "The domain of the account" + }, + "support_email": { + "type": "string", + "description": "The support email of the account" + }, + "status": { + "type": "string", + "description": "The status of the account" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The creation date of the account" + }, + "cache_keys": { + "type": "object", + "description": "Cache keys for the account" + }, + "features": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Enabled features for the account" + }, + "settings": { + "type": "object", + "description": "Account settings", + "properties": { + "auto_resolve_after": { + "type": "number", + "description": "Auto resolve conversations after specified minutes" + }, + "auto_resolve_message": { + "type": "string", + "description": "Message to send when auto resolving" + }, + "auto_resolve_ignore_waiting": { + "type": "boolean", + "description": "Whether to ignore waiting conversations for auto resolve" + } + } + }, + "custom_attributes": { + "type": "object", + "description": "Custom attributes of the account", + "properties": { + "plan_name": { + "type": "string", + "description": "Subscription plan name" + }, + "subscribed_quantity": { + "type": "number", + "description": "Subscribed quantity" + }, + "subscription_status": { + "type": "string", + "description": "Subscription status" + }, + "subscription_ends_on": { + "type": "string", + "format": "date", + "description": "Subscription end date" + }, + "industry": { + "type": "string", + "description": "Industry type" + }, + "company_size": { + "type": "string", + "description": "Company size" + }, + "timezone": { + "type": "string", + "description": "Account timezone" + }, + "logo": { + "type": "string", + "description": "Account logo URL" + }, + "onboarding_step": { + "type": "string", + "description": "Current onboarding step" + }, + "marked_for_deletion_at": { + "type": "string", + "format": "date-time", + "description": "When account was marked for deletion" + }, + "marked_for_deletion_reason": { + "type": "string", + "description": "Reason for account deletion" + } + } + } + } + }, + "account_show_response": { + "allOf": [ + { + "$ref": "#/components/schemas/account_detail" + }, + { + "type": "object", + "properties": { + "latest_chatwoot_version": { + "type": "string", + "description": "Latest version of Chatwoot available", + "example": "3.0.0" + }, + "subscribed_features": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of subscribed enterprise features (if enterprise edition is enabled)" + } + } + } + ] + }, "account_user": { "type": "array", "description": "Array of account users", @@ -9113,6 +9384,66 @@ } } }, + "account_update_payload": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the account", + "example": "My Account" + }, + "locale": { + "type": "string", + "description": "The locale of the account", + "example": "en" + }, + "domain": { + "type": "string", + "description": "The domain of the account", + "example": "example.com" + }, + "support_email": { + "type": "string", + "description": "The support email of the account", + "example": "support@example.com" + }, + "auto_resolve_after": { + "type": "integer", + "minimum": 10, + "maximum": 1439856, + "nullable": true, + "description": "Auto resolve conversations after specified minutes", + "example": 1440 + }, + "auto_resolve_message": { + "type": "string", + "nullable": true, + "description": "Message to send when auto resolving", + "example": "This conversation has been automatically resolved due to inactivity" + }, + "auto_resolve_ignore_waiting": { + "type": "boolean", + "nullable": true, + "description": "Whether to ignore waiting conversations for auto resolve", + "example": false + }, + "industry": { + "type": "string", + "description": "Industry type", + "example": "Technology" + }, + "company_size": { + "type": "string", + "description": "Company size", + "example": "50-100" + }, + "timezone": { + "type": "string", + "description": "Account timezone", + "example": "UTC" + } + } + }, "account_user_create_update_payload": { "type": "object", "required": [ diff --git a/swagger/tag_groups/application_swagger.json b/swagger/tag_groups/application_swagger.json index 33e75183f..2a8162358 100644 --- a/swagger/tag_groups/application_swagger.json +++ b/swagger/tag_groups/application_swagger.json @@ -7135,6 +7135,145 @@ } } }, + "account_detail": { + "type": "object", + "properties": { + "id": { + "type": "number", + "description": "Account ID" + }, + "name": { + "type": "string", + "description": "Name of the account" + }, + "locale": { + "type": "string", + "description": "The locale of the account" + }, + "domain": { + "type": "string", + "description": "The domain of the account" + }, + "support_email": { + "type": "string", + "description": "The support email of the account" + }, + "status": { + "type": "string", + "description": "The status of the account" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The creation date of the account" + }, + "cache_keys": { + "type": "object", + "description": "Cache keys for the account" + }, + "features": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Enabled features for the account" + }, + "settings": { + "type": "object", + "description": "Account settings", + "properties": { + "auto_resolve_after": { + "type": "number", + "description": "Auto resolve conversations after specified minutes" + }, + "auto_resolve_message": { + "type": "string", + "description": "Message to send when auto resolving" + }, + "auto_resolve_ignore_waiting": { + "type": "boolean", + "description": "Whether to ignore waiting conversations for auto resolve" + } + } + }, + "custom_attributes": { + "type": "object", + "description": "Custom attributes of the account", + "properties": { + "plan_name": { + "type": "string", + "description": "Subscription plan name" + }, + "subscribed_quantity": { + "type": "number", + "description": "Subscribed quantity" + }, + "subscription_status": { + "type": "string", + "description": "Subscription status" + }, + "subscription_ends_on": { + "type": "string", + "format": "date", + "description": "Subscription end date" + }, + "industry": { + "type": "string", + "description": "Industry type" + }, + "company_size": { + "type": "string", + "description": "Company size" + }, + "timezone": { + "type": "string", + "description": "Account timezone" + }, + "logo": { + "type": "string", + "description": "Account logo URL" + }, + "onboarding_step": { + "type": "string", + "description": "Current onboarding step" + }, + "marked_for_deletion_at": { + "type": "string", + "format": "date-time", + "description": "When account was marked for deletion" + }, + "marked_for_deletion_reason": { + "type": "string", + "description": "Reason for account deletion" + } + } + } + } + }, + "account_show_response": { + "allOf": [ + { + "$ref": "#/components/schemas/account_detail" + }, + { + "type": "object", + "properties": { + "latest_chatwoot_version": { + "type": "string", + "description": "Latest version of Chatwoot available", + "example": "3.0.0" + }, + "subscribed_features": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of subscribed enterprise features (if enterprise edition is enabled)" + } + } + } + ] + }, "account_user": { "type": "array", "description": "Array of account users", @@ -7474,6 +7613,66 @@ } } }, + "account_update_payload": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the account", + "example": "My Account" + }, + "locale": { + "type": "string", + "description": "The locale of the account", + "example": "en" + }, + "domain": { + "type": "string", + "description": "The domain of the account", + "example": "example.com" + }, + "support_email": { + "type": "string", + "description": "The support email of the account", + "example": "support@example.com" + }, + "auto_resolve_after": { + "type": "integer", + "minimum": 10, + "maximum": 1439856, + "nullable": true, + "description": "Auto resolve conversations after specified minutes", + "example": 1440 + }, + "auto_resolve_message": { + "type": "string", + "nullable": true, + "description": "Message to send when auto resolving", + "example": "This conversation has been automatically resolved due to inactivity" + }, + "auto_resolve_ignore_waiting": { + "type": "boolean", + "nullable": true, + "description": "Whether to ignore waiting conversations for auto resolve", + "example": false + }, + "industry": { + "type": "string", + "description": "Industry type", + "example": "Technology" + }, + "company_size": { + "type": "string", + "description": "Company size", + "example": "50-100" + }, + "timezone": { + "type": "string", + "description": "Account timezone", + "example": "UTC" + } + } + }, "account_user_create_update_payload": { "type": "object", "required": [ diff --git a/swagger/tag_groups/client_swagger.json b/swagger/tag_groups/client_swagger.json index 6d471da43..cefc39324 100644 --- a/swagger/tag_groups/client_swagger.json +++ b/swagger/tag_groups/client_swagger.json @@ -1978,6 +1978,145 @@ } } }, + "account_detail": { + "type": "object", + "properties": { + "id": { + "type": "number", + "description": "Account ID" + }, + "name": { + "type": "string", + "description": "Name of the account" + }, + "locale": { + "type": "string", + "description": "The locale of the account" + }, + "domain": { + "type": "string", + "description": "The domain of the account" + }, + "support_email": { + "type": "string", + "description": "The support email of the account" + }, + "status": { + "type": "string", + "description": "The status of the account" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The creation date of the account" + }, + "cache_keys": { + "type": "object", + "description": "Cache keys for the account" + }, + "features": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Enabled features for the account" + }, + "settings": { + "type": "object", + "description": "Account settings", + "properties": { + "auto_resolve_after": { + "type": "number", + "description": "Auto resolve conversations after specified minutes" + }, + "auto_resolve_message": { + "type": "string", + "description": "Message to send when auto resolving" + }, + "auto_resolve_ignore_waiting": { + "type": "boolean", + "description": "Whether to ignore waiting conversations for auto resolve" + } + } + }, + "custom_attributes": { + "type": "object", + "description": "Custom attributes of the account", + "properties": { + "plan_name": { + "type": "string", + "description": "Subscription plan name" + }, + "subscribed_quantity": { + "type": "number", + "description": "Subscribed quantity" + }, + "subscription_status": { + "type": "string", + "description": "Subscription status" + }, + "subscription_ends_on": { + "type": "string", + "format": "date", + "description": "Subscription end date" + }, + "industry": { + "type": "string", + "description": "Industry type" + }, + "company_size": { + "type": "string", + "description": "Company size" + }, + "timezone": { + "type": "string", + "description": "Account timezone" + }, + "logo": { + "type": "string", + "description": "Account logo URL" + }, + "onboarding_step": { + "type": "string", + "description": "Current onboarding step" + }, + "marked_for_deletion_at": { + "type": "string", + "format": "date-time", + "description": "When account was marked for deletion" + }, + "marked_for_deletion_reason": { + "type": "string", + "description": "Reason for account deletion" + } + } + } + } + }, + "account_show_response": { + "allOf": [ + { + "$ref": "#/components/schemas/account_detail" + }, + { + "type": "object", + "properties": { + "latest_chatwoot_version": { + "type": "string", + "description": "Latest version of Chatwoot available", + "example": "3.0.0" + }, + "subscribed_features": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of subscribed enterprise features (if enterprise edition is enabled)" + } + } + } + ] + }, "account_user": { "type": "array", "description": "Array of account users", @@ -2317,6 +2456,66 @@ } } }, + "account_update_payload": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the account", + "example": "My Account" + }, + "locale": { + "type": "string", + "description": "The locale of the account", + "example": "en" + }, + "domain": { + "type": "string", + "description": "The domain of the account", + "example": "example.com" + }, + "support_email": { + "type": "string", + "description": "The support email of the account", + "example": "support@example.com" + }, + "auto_resolve_after": { + "type": "integer", + "minimum": 10, + "maximum": 1439856, + "nullable": true, + "description": "Auto resolve conversations after specified minutes", + "example": 1440 + }, + "auto_resolve_message": { + "type": "string", + "nullable": true, + "description": "Message to send when auto resolving", + "example": "This conversation has been automatically resolved due to inactivity" + }, + "auto_resolve_ignore_waiting": { + "type": "boolean", + "nullable": true, + "description": "Whether to ignore waiting conversations for auto resolve", + "example": false + }, + "industry": { + "type": "string", + "description": "Industry type", + "example": "Technology" + }, + "company_size": { + "type": "string", + "description": "Company size", + "example": "50-100" + }, + "timezone": { + "type": "string", + "description": "Account timezone", + "example": "UTC" + } + } + }, "account_user_create_update_payload": { "type": "object", "required": [ diff --git a/swagger/tag_groups/other_swagger.json b/swagger/tag_groups/other_swagger.json index fc61e8721..2cc045747 100644 --- a/swagger/tag_groups/other_swagger.json +++ b/swagger/tag_groups/other_swagger.json @@ -1393,6 +1393,145 @@ } } }, + "account_detail": { + "type": "object", + "properties": { + "id": { + "type": "number", + "description": "Account ID" + }, + "name": { + "type": "string", + "description": "Name of the account" + }, + "locale": { + "type": "string", + "description": "The locale of the account" + }, + "domain": { + "type": "string", + "description": "The domain of the account" + }, + "support_email": { + "type": "string", + "description": "The support email of the account" + }, + "status": { + "type": "string", + "description": "The status of the account" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The creation date of the account" + }, + "cache_keys": { + "type": "object", + "description": "Cache keys for the account" + }, + "features": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Enabled features for the account" + }, + "settings": { + "type": "object", + "description": "Account settings", + "properties": { + "auto_resolve_after": { + "type": "number", + "description": "Auto resolve conversations after specified minutes" + }, + "auto_resolve_message": { + "type": "string", + "description": "Message to send when auto resolving" + }, + "auto_resolve_ignore_waiting": { + "type": "boolean", + "description": "Whether to ignore waiting conversations for auto resolve" + } + } + }, + "custom_attributes": { + "type": "object", + "description": "Custom attributes of the account", + "properties": { + "plan_name": { + "type": "string", + "description": "Subscription plan name" + }, + "subscribed_quantity": { + "type": "number", + "description": "Subscribed quantity" + }, + "subscription_status": { + "type": "string", + "description": "Subscription status" + }, + "subscription_ends_on": { + "type": "string", + "format": "date", + "description": "Subscription end date" + }, + "industry": { + "type": "string", + "description": "Industry type" + }, + "company_size": { + "type": "string", + "description": "Company size" + }, + "timezone": { + "type": "string", + "description": "Account timezone" + }, + "logo": { + "type": "string", + "description": "Account logo URL" + }, + "onboarding_step": { + "type": "string", + "description": "Current onboarding step" + }, + "marked_for_deletion_at": { + "type": "string", + "format": "date-time", + "description": "When account was marked for deletion" + }, + "marked_for_deletion_reason": { + "type": "string", + "description": "Reason for account deletion" + } + } + } + } + }, + "account_show_response": { + "allOf": [ + { + "$ref": "#/components/schemas/account_detail" + }, + { + "type": "object", + "properties": { + "latest_chatwoot_version": { + "type": "string", + "description": "Latest version of Chatwoot available", + "example": "3.0.0" + }, + "subscribed_features": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of subscribed enterprise features (if enterprise edition is enabled)" + } + } + } + ] + }, "account_user": { "type": "array", "description": "Array of account users", @@ -1732,6 +1871,66 @@ } } }, + "account_update_payload": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the account", + "example": "My Account" + }, + "locale": { + "type": "string", + "description": "The locale of the account", + "example": "en" + }, + "domain": { + "type": "string", + "description": "The domain of the account", + "example": "example.com" + }, + "support_email": { + "type": "string", + "description": "The support email of the account", + "example": "support@example.com" + }, + "auto_resolve_after": { + "type": "integer", + "minimum": 10, + "maximum": 1439856, + "nullable": true, + "description": "Auto resolve conversations after specified minutes", + "example": 1440 + }, + "auto_resolve_message": { + "type": "string", + "nullable": true, + "description": "Message to send when auto resolving", + "example": "This conversation has been automatically resolved due to inactivity" + }, + "auto_resolve_ignore_waiting": { + "type": "boolean", + "nullable": true, + "description": "Whether to ignore waiting conversations for auto resolve", + "example": false + }, + "industry": { + "type": "string", + "description": "Industry type", + "example": "Technology" + }, + "company_size": { + "type": "string", + "description": "Company size", + "example": "50-100" + }, + "timezone": { + "type": "string", + "description": "Account timezone", + "example": "UTC" + } + } + }, "account_user_create_update_payload": { "type": "object", "required": [ diff --git a/swagger/tag_groups/platform_swagger.json b/swagger/tag_groups/platform_swagger.json index 18ec796a0..085e969ab 100644 --- a/swagger/tag_groups/platform_swagger.json +++ b/swagger/tag_groups/platform_swagger.json @@ -2154,6 +2154,145 @@ } } }, + "account_detail": { + "type": "object", + "properties": { + "id": { + "type": "number", + "description": "Account ID" + }, + "name": { + "type": "string", + "description": "Name of the account" + }, + "locale": { + "type": "string", + "description": "The locale of the account" + }, + "domain": { + "type": "string", + "description": "The domain of the account" + }, + "support_email": { + "type": "string", + "description": "The support email of the account" + }, + "status": { + "type": "string", + "description": "The status of the account" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "The creation date of the account" + }, + "cache_keys": { + "type": "object", + "description": "Cache keys for the account" + }, + "features": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Enabled features for the account" + }, + "settings": { + "type": "object", + "description": "Account settings", + "properties": { + "auto_resolve_after": { + "type": "number", + "description": "Auto resolve conversations after specified minutes" + }, + "auto_resolve_message": { + "type": "string", + "description": "Message to send when auto resolving" + }, + "auto_resolve_ignore_waiting": { + "type": "boolean", + "description": "Whether to ignore waiting conversations for auto resolve" + } + } + }, + "custom_attributes": { + "type": "object", + "description": "Custom attributes of the account", + "properties": { + "plan_name": { + "type": "string", + "description": "Subscription plan name" + }, + "subscribed_quantity": { + "type": "number", + "description": "Subscribed quantity" + }, + "subscription_status": { + "type": "string", + "description": "Subscription status" + }, + "subscription_ends_on": { + "type": "string", + "format": "date", + "description": "Subscription end date" + }, + "industry": { + "type": "string", + "description": "Industry type" + }, + "company_size": { + "type": "string", + "description": "Company size" + }, + "timezone": { + "type": "string", + "description": "Account timezone" + }, + "logo": { + "type": "string", + "description": "Account logo URL" + }, + "onboarding_step": { + "type": "string", + "description": "Current onboarding step" + }, + "marked_for_deletion_at": { + "type": "string", + "format": "date-time", + "description": "When account was marked for deletion" + }, + "marked_for_deletion_reason": { + "type": "string", + "description": "Reason for account deletion" + } + } + } + } + }, + "account_show_response": { + "allOf": [ + { + "$ref": "#/components/schemas/account_detail" + }, + { + "type": "object", + "properties": { + "latest_chatwoot_version": { + "type": "string", + "description": "Latest version of Chatwoot available", + "example": "3.0.0" + }, + "subscribed_features": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of subscribed enterprise features (if enterprise edition is enabled)" + } + } + } + ] + }, "account_user": { "type": "array", "description": "Array of account users", @@ -2493,6 +2632,66 @@ } } }, + "account_update_payload": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Name of the account", + "example": "My Account" + }, + "locale": { + "type": "string", + "description": "The locale of the account", + "example": "en" + }, + "domain": { + "type": "string", + "description": "The domain of the account", + "example": "example.com" + }, + "support_email": { + "type": "string", + "description": "The support email of the account", + "example": "support@example.com" + }, + "auto_resolve_after": { + "type": "integer", + "minimum": 10, + "maximum": 1439856, + "nullable": true, + "description": "Auto resolve conversations after specified minutes", + "example": 1440 + }, + "auto_resolve_message": { + "type": "string", + "nullable": true, + "description": "Message to send when auto resolving", + "example": "This conversation has been automatically resolved due to inactivity" + }, + "auto_resolve_ignore_waiting": { + "type": "boolean", + "nullable": true, + "description": "Whether to ignore waiting conversations for auto resolve", + "example": false + }, + "industry": { + "type": "string", + "description": "Industry type", + "example": "Technology" + }, + "company_size": { + "type": "string", + "description": "Company size", + "example": "50-100" + }, + "timezone": { + "type": "string", + "description": "Account timezone", + "example": "UTC" + } + } + }, "account_user_create_update_payload": { "type": "object", "required": [ From 23a804512aed3849f4500ecf76961516a6d4f8dc Mon Sep 17 00:00:00 2001 From: Pranav Date: Thu, 29 May 2025 01:05:10 -0600 Subject: [PATCH 03/16] feat: Update the UI to support the change for Copilot as a universal copilot (#11618) Co-authored-by: Shivam Mishra Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> --- .../dashboard/assets/scss/widgets/_tabs.scss | 2 +- .../Conversation/SidepanelSwitch.vue | 87 +++++++++++++++++++ ...ory.vue => SidebarActionsHeader.story.vue} | 16 +++- .../components-next/SidebarActionsHeader.vue | 47 ++++++++++ .../components-next/copilot/Copilot.vue | 43 ++++++--- .../components-next/copilot/CopilotHeader.vue | 32 ------- .../components-next/sidebar/Sidebar.vue | 2 +- .../dashboard/components/ChatList.vue | 2 +- .../dashboard/components/ChatListHeader.vue | 8 +- .../components/widgets/ChatTypeTabs.vue | 3 +- .../widgets/conversation/ConversationBox.vue | 21 +---- .../widgets/conversation/ConversationCard.vue | 4 +- .../conversation/ConversationHeader.vue | 38 ++------ .../conversation/ConversationSidebar.vue | 60 +++++-------- .../widgets/conversation/MessagesView.vue | 36 -------- .../dashboard/i18n/locale/en/general.json | 3 +- .../dashboard/conversation/ContactPanel.vue | 25 +++--- .../conversation/ConversationView.vue | 32 ++++--- 18 files changed, 248 insertions(+), 213 deletions(-) create mode 100644 app/javascript/dashboard/components-next/Conversation/SidepanelSwitch.vue rename app/javascript/dashboard/components-next/{copilot/CopilotHeader.story.vue => SidebarActionsHeader.story.vue} (50%) create mode 100644 app/javascript/dashboard/components-next/SidebarActionsHeader.vue delete mode 100644 app/javascript/dashboard/components-next/copilot/CopilotHeader.vue diff --git a/app/javascript/dashboard/assets/scss/widgets/_tabs.scss b/app/javascript/dashboard/assets/scss/widgets/_tabs.scss index 72a2e6be8..72773de7f 100644 --- a/app/javascript/dashboard/assets/scss/widgets/_tabs.scss +++ b/app/javascript/dashboard/assets/scss/widgets/_tabs.scss @@ -3,7 +3,7 @@ } .tabs--container--with-border { - @apply border-b border-n-weak; + @apply border-b border-b-n-weak; } .tabs--container--compact.tab--chat-type { diff --git a/app/javascript/dashboard/components-next/Conversation/SidepanelSwitch.vue b/app/javascript/dashboard/components-next/Conversation/SidepanelSwitch.vue new file mode 100644 index 000000000..ec3a8d03a --- /dev/null +++ b/app/javascript/dashboard/components-next/Conversation/SidepanelSwitch.vue @@ -0,0 +1,87 @@ + + + diff --git a/app/javascript/dashboard/components-next/copilot/CopilotHeader.story.vue b/app/javascript/dashboard/components-next/SidebarActionsHeader.story.vue similarity index 50% rename from app/javascript/dashboard/components-next/copilot/CopilotHeader.story.vue rename to app/javascript/dashboard/components-next/SidebarActionsHeader.story.vue index 78a345093..13d528240 100644 --- a/app/javascript/dashboard/components-next/copilot/CopilotHeader.story.vue +++ b/app/javascript/dashboard/components-next/SidebarActionsHeader.story.vue @@ -1,21 +1,29 @@ diff --git a/app/javascript/dashboard/components-next/SidebarActionsHeader.vue b/app/javascript/dashboard/components-next/SidebarActionsHeader.vue new file mode 100644 index 000000000..210ddfa0e --- /dev/null +++ b/app/javascript/dashboard/components-next/SidebarActionsHeader.vue @@ -0,0 +1,47 @@ + + + diff --git a/app/javascript/dashboard/components-next/copilot/Copilot.vue b/app/javascript/dashboard/components-next/copilot/Copilot.vue index 5feb474a6..6fb45c278 100644 --- a/app/javascript/dashboard/components-next/copilot/Copilot.vue +++ b/app/javascript/dashboard/components-next/copilot/Copilot.vue @@ -3,13 +3,15 @@ import { nextTick, ref, watch } from 'vue'; import { useI18n } from 'vue-i18n'; import { useTrack } from 'dashboard/composables'; import { COPILOT_EVENTS } from 'dashboard/helper/AnalyticsHelper/events'; +import { useUISettings } from 'dashboard/composables/useUISettings'; import CopilotInput from './CopilotInput.vue'; import CopilotLoader from './CopilotLoader.vue'; import CopilotAgentMessage from './CopilotAgentMessage.vue'; import CopilotAssistantMessage from './CopilotAssistantMessage.vue'; import ToggleCopilotAssistant from './ToggleCopilotAssistant.vue'; -import Icon from '../icon/Icon.vue'; +import Icon from 'dashboard/components-next/icon/Icon.vue'; +import SidebarActionsHeader from 'dashboard/components-next/SidebarActionsHeader.vue'; const props = defineProps({ supportAgent: { @@ -54,10 +56,6 @@ const useSuggestion = opt => { useTrack(COPILOT_EVENTS.SEND_SUGGESTED); }; -const handleReset = () => { - emit('reset'); -}; - const chatContainer = ref(null); const scrollToBottom = async () => { @@ -82,6 +80,21 @@ const promptOptions = [ }, ]; +const { updateUISettings } = useUISettings(); + +const closeCopilotPanel = () => { + updateUISettings({ + is_copilot_panel_open: false, + is_contact_sidebar_open: false, + }); +}; + +const handleSidebarAction = action => { + if (action === 'reset') { + emit('reset'); + } +}; + watch( [() => props.messages, () => props.isCaptainTyping], () => { @@ -93,6 +106,18 @@ watch(