Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f9e94af2e | ||
|
|
cf73ba195e |
@@ -10,8 +10,7 @@ function toggleSecretField(e) {
|
|||||||
if (!textElement) return;
|
if (!textElement) return;
|
||||||
|
|
||||||
if (textElement.dataset.secretMasked === 'false') {
|
if (textElement.dataset.secretMasked === 'false') {
|
||||||
const maskedLength = secretField.dataset.secretText?.length || 10;
|
textElement.textContent = '•'.repeat(10);
|
||||||
textElement.textContent = '•'.repeat(maskedLength);
|
|
||||||
textElement.dataset.secretMasked = 'true';
|
textElement.dataset.secretMasked = 'true';
|
||||||
toggler.querySelector('svg use').setAttribute('xlink:href', '#eye-show');
|
toggler.querySelector('svg use').setAttribute('xlink:href', '#eye-show');
|
||||||
|
|
||||||
@@ -33,13 +32,3 @@ function copySecretField(e) {
|
|||||||
|
|
||||||
navigator.clipboard.writeText(secretField.dataset.secretText);
|
navigator.clipboard.writeText(secretField.dataset.secretText);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
document.querySelectorAll('.cell-data__secret-field').forEach(field => {
|
|
||||||
const span = field.querySelector('[data-secret-masked]');
|
|
||||||
if (span && span.dataset.secretMasked === 'true') {
|
|
||||||
const len = field.dataset.secretText?.length || 10;
|
|
||||||
span.textContent = '•'.repeat(len);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -46,25 +46,17 @@
|
|||||||
|
|
||||||
.cell-data__secret-field {
|
.cell-data__secret-field {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: $hint-grey;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
flex: 0 0 auto;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-secret-toggler],
|
button {
|
||||||
[data-secret-copier] {
|
margin-left: 5px;
|
||||||
background: transparent;
|
|
||||||
border: 0;
|
|
||||||
color: inherit;
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
height: 1.25rem;
|
|
||||||
width: 1.25rem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class V2::Reports::LabelSummaryBuilder < V2::Reports::BaseSummaryBuilder
|
|||||||
resolved_counts: fetch_resolved_counts(conversation_filter),
|
resolved_counts: fetch_resolved_counts(conversation_filter),
|
||||||
resolution_metrics: fetch_metrics(conversation_filter, 'conversation_resolved', use_business_hours),
|
resolution_metrics: fetch_metrics(conversation_filter, 'conversation_resolved', use_business_hours),
|
||||||
first_response_metrics: fetch_metrics(conversation_filter, 'first_response', use_business_hours),
|
first_response_metrics: fetch_metrics(conversation_filter, 'first_response', use_business_hours),
|
||||||
reply_metrics: fetch_metrics(conversation_filter, 'reply_time', use_business_hours)
|
reply_metrics: fetch_metrics(conversation_filter, 'reply', use_business_hours)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -63,9 +63,7 @@ class V2::Reports::LabelSummaryBuilder < V2::Reports::BaseSummaryBuilder
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_resolved_counts(conversation_filter)
|
def fetch_resolved_counts(conversation_filter)
|
||||||
# since the base query is ActsAsTaggableOn,
|
fetch_counts(conversation_filter.merge(status: :resolved))
|
||||||
# the status :resolved won't automatically be converted to integer status
|
|
||||||
fetch_counts(conversation_filter.merge(status: Conversation.statuses[:resolved]))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_counts(conversation_filter)
|
def fetch_counts(conversation_filter)
|
||||||
|
|||||||
@@ -1,23 +1,32 @@
|
|||||||
class Api::V1::Accounts::Google::AuthorizationsController < Api::V1::Accounts::OauthAuthorizationController
|
class Api::V1::Accounts::Google::AuthorizationsController < Api::V1::Accounts::BaseController
|
||||||
include GoogleConcern
|
include GoogleConcern
|
||||||
|
before_action :check_authorization
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
email = params[:authorization][:email]
|
||||||
redirect_url = google_client.auth_code.authorize_url(
|
redirect_url = google_client.auth_code.authorize_url(
|
||||||
{
|
{
|
||||||
redirect_uri: "#{base_url}/google/callback",
|
redirect_uri: "#{base_url}/google/callback",
|
||||||
scope: scope,
|
scope: 'email profile https://mail.google.com/',
|
||||||
response_type: 'code',
|
response_type: 'code',
|
||||||
prompt: 'consent', # the oauth flow does not return a refresh token, this is supposed to fix it
|
prompt: 'consent', # the oauth flow does not return a refresh token, this is supposed to fix it
|
||||||
access_type: 'offline', # the default is 'online'
|
access_type: 'offline', # the default is 'online'
|
||||||
state: state,
|
|
||||||
client_id: GlobalConfigService.load('GOOGLE_OAUTH_CLIENT_ID', nil)
|
client_id: GlobalConfigService.load('GOOGLE_OAUTH_CLIENT_ID', nil)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
if redirect_url
|
if redirect_url
|
||||||
|
cache_key = "google::#{email.downcase}"
|
||||||
|
::Redis::Alfred.setex(cache_key, Current.account.id, 5.minutes)
|
||||||
render json: { success: true, url: redirect_url }
|
render json: { success: true, url: redirect_url }
|
||||||
else
|
else
|
||||||
render json: { success: false }, status: :unprocessable_entity
|
render json: { success: false }, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_authorization
|
||||||
|
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
class Api::V1::Accounts::Instagram::AuthorizationsController < Api::V1::Accounts::OauthAuthorizationController
|
class Api::V1::Accounts::Instagram::AuthorizationsController < Api::V1::Accounts::BaseController
|
||||||
include InstagramConcern
|
include InstagramConcern
|
||||||
include Instagram::IntegrationHelper
|
include Instagram::IntegrationHelper
|
||||||
|
before_action :check_authorization
|
||||||
|
|
||||||
def create
|
def create
|
||||||
# https://developers.facebook.com/docs/instagram-platform/instagram-api-with-instagram-login/business-login#step-1--get-authorization
|
# https://developers.facebook.com/docs/instagram-platform/instagram-api-with-instagram-login/business-login#step-1--get-authorization
|
||||||
@@ -20,4 +21,10 @@ class Api::V1::Accounts::Instagram::AuthorizationsController < Api::V1::Accounts
|
|||||||
render json: { success: false }, status: :unprocessable_entity
|
render json: { success: false }, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_authorization
|
||||||
|
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
class Api::V1::Accounts::Integrations::GithubController < Api::V1::Accounts::BaseController
|
||||||
|
before_action :check_authorization
|
||||||
|
|
||||||
|
def show
|
||||||
|
@github_integration = Current.account.hooks.find_by(app_id: 'github')
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_authorization
|
||||||
|
authorize ::Webhook, :show?
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
class Api::V1::Accounts::Integrations::LinearController < Api::V1::Accounts::BaseController
|
class Api::V1::Accounts::Integrations::LinearController < Api::V1::Accounts::BaseController
|
||||||
before_action :fetch_conversation, only: [:create_issue, :link_issue, :unlink_issue, :linked_issues]
|
before_action :fetch_conversation, only: [:link_issue, :linked_issues]
|
||||||
before_action :fetch_hook, only: [:destroy]
|
before_action :fetch_hook, only: [:destroy]
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@@ -31,12 +31,6 @@ class Api::V1::Accounts::Integrations::LinearController < Api::V1::Accounts::Bas
|
|||||||
if issue[:error]
|
if issue[:error]
|
||||||
render json: { error: issue[:error] }, status: :unprocessable_entity
|
render json: { error: issue[:error] }, status: :unprocessable_entity
|
||||||
else
|
else
|
||||||
Linear::ActivityMessageService.new(
|
|
||||||
conversation: @conversation,
|
|
||||||
action_type: :issue_created,
|
|
||||||
issue_data: { id: issue[:data][:identifier] },
|
|
||||||
user: Current.user
|
|
||||||
).perform
|
|
||||||
render json: issue[:data], status: :ok
|
render json: issue[:data], status: :ok
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -48,30 +42,17 @@ class Api::V1::Accounts::Integrations::LinearController < Api::V1::Accounts::Bas
|
|||||||
if issue[:error]
|
if issue[:error]
|
||||||
render json: { error: issue[:error] }, status: :unprocessable_entity
|
render json: { error: issue[:error] }, status: :unprocessable_entity
|
||||||
else
|
else
|
||||||
Linear::ActivityMessageService.new(
|
|
||||||
conversation: @conversation,
|
|
||||||
action_type: :issue_linked,
|
|
||||||
issue_data: { id: issue_id },
|
|
||||||
user: Current.user
|
|
||||||
).perform
|
|
||||||
render json: issue[:data], status: :ok
|
render json: issue[:data], status: :ok
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def unlink_issue
|
def unlink_issue
|
||||||
link_id = permitted_params[:link_id]
|
link_id = permitted_params[:link_id]
|
||||||
issue_id = permitted_params[:issue_id]
|
|
||||||
issue = linear_processor_service.unlink_issue(link_id)
|
issue = linear_processor_service.unlink_issue(link_id)
|
||||||
|
|
||||||
if issue[:error]
|
if issue[:error]
|
||||||
render json: { error: issue[:error] }, status: :unprocessable_entity
|
render json: { error: issue[:error] }, status: :unprocessable_entity
|
||||||
else
|
else
|
||||||
Linear::ActivityMessageService.new(
|
|
||||||
conversation: @conversation,
|
|
||||||
action_type: :issue_unlinked,
|
|
||||||
issue_data: { id: issue_id },
|
|
||||||
user: Current.user
|
|
||||||
).perform
|
|
||||||
render json: issue[:data], status: :ok
|
render json: issue[:data], status: :ok
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
class Api::V1::Accounts::Integrations::NotionController < Api::V1::Accounts::BaseController
|
|
||||||
before_action :fetch_hook, only: [:destroy]
|
|
||||||
|
|
||||||
def destroy
|
|
||||||
@hook.destroy!
|
|
||||||
head :ok
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def fetch_hook
|
|
||||||
@hook = Integrations::Hook.where(account: Current.account).find_by(app_id: 'notion')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,19 +1,28 @@
|
|||||||
class Api::V1::Accounts::Microsoft::AuthorizationsController < Api::V1::Accounts::OauthAuthorizationController
|
class Api::V1::Accounts::Microsoft::AuthorizationsController < Api::V1::Accounts::BaseController
|
||||||
include MicrosoftConcern
|
include MicrosoftConcern
|
||||||
|
before_action :check_authorization
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
email = params[:authorization][:email]
|
||||||
redirect_url = microsoft_client.auth_code.authorize_url(
|
redirect_url = microsoft_client.auth_code.authorize_url(
|
||||||
{
|
{
|
||||||
redirect_uri: "#{base_url}/microsoft/callback",
|
redirect_uri: "#{base_url}/microsoft/callback",
|
||||||
scope: scope,
|
scope: 'offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send openid profile',
|
||||||
state: state,
|
|
||||||
prompt: 'consent'
|
prompt: 'consent'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if redirect_url
|
if redirect_url
|
||||||
|
cache_key = "microsoft::#{email.downcase}"
|
||||||
|
::Redis::Alfred.setex(cache_key, Current.account.id, 5.minutes)
|
||||||
render json: { success: true, url: redirect_url }
|
render json: { success: true, url: redirect_url }
|
||||||
else
|
else
|
||||||
render json: { success: false }, status: :unprocessable_entity
|
render json: { success: false }, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def check_authorization
|
||||||
|
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
class Api::V1::Accounts::Notion::AuthorizationsController < Api::V1::Accounts::OauthAuthorizationController
|
|
||||||
include NotionConcern
|
|
||||||
|
|
||||||
def create
|
|
||||||
redirect_url = notion_client.auth_code.authorize_url(
|
|
||||||
{
|
|
||||||
redirect_uri: "#{base_url}/notion/callback",
|
|
||||||
response_type: 'code',
|
|
||||||
owner: 'user',
|
|
||||||
state: state,
|
|
||||||
client_id: GlobalConfigService.load('NOTION_CLIENT_ID', nil)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if redirect_url
|
|
||||||
render json: { success: true, url: redirect_url }
|
|
||||||
else
|
|
||||||
render json: { success: false }, status: :unprocessable_entity
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
class Api::V1::Accounts::OauthAuthorizationController < Api::V1::Accounts::BaseController
|
|
||||||
before_action :check_authorization
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def scope
|
|
||||||
''
|
|
||||||
end
|
|
||||||
|
|
||||||
def state
|
|
||||||
Current.account.to_sgid(expires_in: 15.minutes).to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def base_url
|
|
||||||
ENV.fetch('FRONTEND_URL', 'http://localhost:3000')
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def check_authorization
|
|
||||||
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -14,7 +14,7 @@ module GoogleConcern
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def scope
|
def base_url
|
||||||
'email profile https://mail.google.com/'
|
ENV.fetch('FRONTEND_URL', 'http://localhost:3000')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ module MicrosoftConcern
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def scope
|
def base_url
|
||||||
'offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send openid profile email'
|
ENV.fetch('FRONTEND_URL', 'http://localhost:3000')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
module NotionConcern
|
|
||||||
extend ActiveSupport::Concern
|
|
||||||
|
|
||||||
def notion_client
|
|
||||||
app_id = GlobalConfigService.load('NOTION_CLIENT_ID', nil)
|
|
||||||
app_secret = GlobalConfigService.load('NOTION_CLIENT_SECRET', nil)
|
|
||||||
|
|
||||||
::OAuth2::Client.new(app_id, app_secret, {
|
|
||||||
site: 'https://api.notion.com',
|
|
||||||
authorize_url: 'https://api.notion.com/v1/oauth/authorize',
|
|
||||||
token_url: 'https://api.notion.com/v1/oauth/token',
|
|
||||||
auth_scheme: :basic_auth
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def scope
|
|
||||||
'read'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
class Github::CallbacksController < ApplicationController
|
||||||
|
include Github::IntegrationHelper
|
||||||
|
before_action :authenticate_user!
|
||||||
|
before_action :set_account
|
||||||
|
|
||||||
|
def show
|
||||||
|
if params[:error].present?
|
||||||
|
redirect_to app_account_integrations_path(account_id: @account.id), alert: params[:error_description]
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if params[:code].present?
|
||||||
|
response = exchange_code_for_token(params[:code])
|
||||||
|
|
||||||
|
if response[:access_token].present?
|
||||||
|
hook = @account.hooks.find_or_initialize_by(app_id: 'github')
|
||||||
|
hook.access_token = response[:access_token]
|
||||||
|
hook.status = 'enabled'
|
||||||
|
|
||||||
|
if hook.save
|
||||||
|
redirect_to app_account_integrations_path(account_id: @account.id), notice: 'GitHub integration connected successfully!'
|
||||||
|
else
|
||||||
|
redirect_to app_account_integrations_path(account_id: @account.id), alert: 'Failed to save GitHub integration'
|
||||||
|
end
|
||||||
|
else
|
||||||
|
redirect_to app_account_integrations_path(account_id: @account.id), alert: 'Failed to get access token from GitHub'
|
||||||
|
end
|
||||||
|
else
|
||||||
|
redirect_to app_account_integrations_path(account_id: @account.id), alert: 'GitHub authorization failed'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_account
|
||||||
|
@account = Current.user.accounts.find(params[:account_id]) if params[:account_id].present?
|
||||||
|
@account ||= Current.user.accounts.first
|
||||||
|
|
||||||
|
return if @account
|
||||||
|
|
||||||
|
redirect_to root_path, alert: 'Account not found'
|
||||||
|
end
|
||||||
|
|
||||||
|
def exchange_code_for_token(code)
|
||||||
|
client_id = GlobalConfigService.load('GITHUB_CLIENT_ID', nil)
|
||||||
|
client_secret = GlobalConfigService.load('GITHUB_CLIENT_SECRET', nil)
|
||||||
|
|
||||||
|
return {} unless client_id && client_secret
|
||||||
|
|
||||||
|
response = HTTParty.post('https://github.com/login/oauth/access_token', {
|
||||||
|
body: {
|
||||||
|
client_id: client_id,
|
||||||
|
client_secret: client_secret,
|
||||||
|
code: code
|
||||||
|
},
|
||||||
|
headers: {
|
||||||
|
'Accept' => 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if response.success?
|
||||||
|
JSON.parse(response.body).with_indifferent_access
|
||||||
|
else
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
rescue StandardError => e
|
||||||
|
Rails.logger.error "GitHub OAuth error: #{e.message}"
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
class Notion::CallbacksController < OauthCallbackController
|
|
||||||
include NotionConcern
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def provider_name
|
|
||||||
'notion'
|
|
||||||
end
|
|
||||||
|
|
||||||
def oauth_client
|
|
||||||
notion_client
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_response
|
|
||||||
hook = account.hooks.new(
|
|
||||||
access_token: parsed_body['access_token'],
|
|
||||||
status: 'enabled',
|
|
||||||
app_id: 'notion',
|
|
||||||
settings: {
|
|
||||||
token_type: parsed_body['token_type'],
|
|
||||||
workspace_name: parsed_body['workspace_name'],
|
|
||||||
workspace_id: parsed_body['workspace_id'],
|
|
||||||
workspace_icon: parsed_body['workspace_icon'],
|
|
||||||
bot_id: parsed_body['bot_id'],
|
|
||||||
owner: parsed_body['owner']
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
hook.save!
|
|
||||||
redirect_to notion_redirect_uri
|
|
||||||
end
|
|
||||||
|
|
||||||
def notion_redirect_uri
|
|
||||||
"#{ENV.fetch('FRONTEND_URL', nil)}/app/accounts/#{account.id}/settings/integrations/notion"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -6,6 +6,7 @@ class OauthCallbackController < ApplicationController
|
|||||||
)
|
)
|
||||||
|
|
||||||
handle_response
|
handle_response
|
||||||
|
::Redis::Alfred.delete(cache_key)
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
ChatwootExceptionTracker.new(e).capture_exception
|
ChatwootExceptionTracker.new(e).capture_exception
|
||||||
redirect_to '/'
|
redirect_to '/'
|
||||||
@@ -63,6 +64,10 @@ class OauthCallbackController < ApplicationController
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cache_key
|
||||||
|
"#{provider_name}::#{users_data['email'].downcase}"
|
||||||
|
end
|
||||||
|
|
||||||
def create_channel_with_inbox
|
def create_channel_with_inbox
|
||||||
ActiveRecord::Base.transaction do
|
ActiveRecord::Base.transaction do
|
||||||
channel_email = Channel::Email.create!(email: users_data['email'], account: account)
|
channel_email = Channel::Email.create!(email: users_data['email'], account: account)
|
||||||
@@ -81,17 +86,12 @@ class OauthCallbackController < ApplicationController
|
|||||||
decoded_token[0]
|
decoded_token[0]
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_from_signed_id
|
def account_id
|
||||||
raise ActionController::BadRequest, 'Missing state variable' if params[:state].blank?
|
::Redis::Alfred.get(cache_key)
|
||||||
|
|
||||||
account = GlobalID::Locator.locate_signed(params[:state])
|
|
||||||
raise 'Invalid or expired state' if account.nil?
|
|
||||||
|
|
||||||
account
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def account
|
def account
|
||||||
@account ||= account_from_signed_id
|
@account ||= Account.find(account_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Fallback name, for when name field is missing from users_data
|
# Fallback name, for when name field is missing from users_data
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ class SuperAdmin::AppConfigsController < SuperAdmin::ApplicationController
|
|||||||
'email' => ['MAILER_INBOUND_EMAIL_DOMAIN'],
|
'email' => ['MAILER_INBOUND_EMAIL_DOMAIN'],
|
||||||
'linear' => %w[LINEAR_CLIENT_ID LINEAR_CLIENT_SECRET],
|
'linear' => %w[LINEAR_CLIENT_ID LINEAR_CLIENT_SECRET],
|
||||||
'slack' => %w[SLACK_CLIENT_ID SLACK_CLIENT_SECRET],
|
'slack' => %w[SLACK_CLIENT_ID SLACK_CLIENT_SECRET],
|
||||||
'notion' => %w[NOTION_CLIENT_ID NOTION_CLIENT_SECRET],
|
'instagram' => %w[INSTAGRAM_APP_ID INSTAGRAM_APP_SECRET INSTAGRAM_VERIFY_TOKEN INSTAGRAM_API_VERSION ENABLE_INSTAGRAM_CHANNEL_HUMAN_AGENT],
|
||||||
'instagram' => %w[INSTAGRAM_APP_ID INSTAGRAM_APP_SECRET INSTAGRAM_VERIFY_TOKEN INSTAGRAM_API_VERSION ENABLE_INSTAGRAM_CHANNEL_HUMAN_AGENT]
|
'github' => %w[GITHUB_CLIENT_ID GITHUB_CLIENT_SECRET]
|
||||||
}
|
}
|
||||||
|
|
||||||
@allowed_configs = mapping.fetch(@config, %w[ENABLE_ACCOUNT_SIGNUP FIREBASE_PROJECT_ID FIREBASE_CREDENTIALS])
|
@allowed_configs = mapping.fetch(@config, %w[ENABLE_ACCOUNT_SIGNUP FIREBASE_PROJECT_ID FIREBASE_CREDENTIALS])
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
module Github::IntegrationHelper
|
||||||
|
def github_integration_url(account_id)
|
||||||
|
"#{ENV.fetch('FRONTEND_URL', nil)}/github/callback?account_id=#{account_id}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def github_oauth_url(account_id)
|
||||||
|
client_id = GlobalConfigService.load('GITHUB_CLIENT_ID', nil)
|
||||||
|
return nil unless client_id
|
||||||
|
|
||||||
|
params = {
|
||||||
|
client_id: client_id,
|
||||||
|
redirect_uri: github_integration_url(account_id),
|
||||||
|
scope: 'repo',
|
||||||
|
state: generate_state_token(account_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
"https://github.com/login/oauth/authorize?#{params.to_query}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def github_configured?
|
||||||
|
GlobalConfigService.load('GITHUB_CLIENT_ID', nil).present? &&
|
||||||
|
GlobalConfigService.load('GITHUB_CLIENT_SECRET', nil).present?
|
||||||
|
end
|
||||||
|
|
||||||
|
def github_integration_enabled?(account)
|
||||||
|
return false unless github_configured?
|
||||||
|
|
||||||
|
account.hooks.exists?(app_id: 'github', status: 'enabled')
|
||||||
|
end
|
||||||
|
|
||||||
|
def github_repositories(access_token)
|
||||||
|
return [] unless access_token
|
||||||
|
|
||||||
|
response = HTTParty.get('https://api.github.com/user/repos', {
|
||||||
|
headers: {
|
||||||
|
'Authorization' => "token #{access_token}",
|
||||||
|
'Accept' => 'application/vnd.github.v3+json'
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
per_page: 100,
|
||||||
|
sort: 'updated'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if response.success?
|
||||||
|
JSON.parse(response.body)
|
||||||
|
else
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
rescue StandardError => e
|
||||||
|
Rails.logger.error "GitHub API error: #{e.message}"
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def generate_state_token(account_id)
|
||||||
|
payload = {
|
||||||
|
account_id: account_id,
|
||||||
|
timestamp: Time.current.to_i
|
||||||
|
}
|
||||||
|
|
||||||
|
JWT.encode(payload, Rails.application.secret_key_base, 'HS256')
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_state_token(state)
|
||||||
|
JWT.decode(state, Rails.application.secret_key_base, true, { algorithm: 'HS256' })
|
||||||
|
rescue JWT::DecodeError
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -33,11 +33,9 @@ class LinearAPI extends ApiClient {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlinkIssue(linkId, issueIdentifier, conversationId) {
|
unlinkIssue(linkId) {
|
||||||
return axios.post(`${this.url}/unlink_issue`, {
|
return axios.post(`${this.url}/unlink_issue`, {
|
||||||
link_id: linkId,
|
link_id: linkId,
|
||||||
issue_id: issueIdentifier,
|
|
||||||
conversation_id: conversationId,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
/* global axios */
|
|
||||||
import ApiClient from './ApiClient';
|
|
||||||
|
|
||||||
class NotionOAuthClient extends ApiClient {
|
|
||||||
constructor() {
|
|
||||||
super('notion', { accountScoped: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
generateAuthorization() {
|
|
||||||
return axios.post(`${this.url}/authorization`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new NotionOAuthClient();
|
|
||||||
@@ -91,19 +91,6 @@ describe('#linearAPI', () => {
|
|||||||
issueData
|
issueData
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates a valid request with conversation_id', () => {
|
|
||||||
const issueData = {
|
|
||||||
title: 'New Issue',
|
|
||||||
description: 'Issue description',
|
|
||||||
conversation_id: 123,
|
|
||||||
};
|
|
||||||
LinearAPIClient.createIssue(issueData);
|
|
||||||
expect(axiosMock.post).toHaveBeenCalledWith(
|
|
||||||
'/api/v1/integrations/linear/create_issue',
|
|
||||||
issueData
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('link_issue', () => {
|
describe('link_issue', () => {
|
||||||
@@ -133,18 +120,6 @@ describe('#linearAPI', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates a valid request with title', () => {
|
|
||||||
LinearAPIClient.link_issue(1, 'ENG-123', 'Sample Issue');
|
|
||||||
expect(axiosMock.post).toHaveBeenCalledWith(
|
|
||||||
'/api/v1/integrations/linear/link_issue',
|
|
||||||
{
|
|
||||||
issue_id: 'ENG-123',
|
|
||||||
conversation_id: 1,
|
|
||||||
title: 'Sample Issue',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('getLinkedIssue', () => {
|
describe('getLinkedIssue', () => {
|
||||||
@@ -189,26 +164,12 @@ describe('#linearAPI', () => {
|
|||||||
window.axios = originalAxios;
|
window.axios = originalAxios;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates a valid request with link_id only', () => {
|
it('creates a valid request', () => {
|
||||||
LinearAPIClient.unlinkIssue('link123');
|
LinearAPIClient.unlinkIssue(1);
|
||||||
expect(axiosMock.post).toHaveBeenCalledWith(
|
expect(axiosMock.post).toHaveBeenCalledWith(
|
||||||
'/api/v1/integrations/linear/unlink_issue',
|
'/api/v1/integrations/linear/unlink_issue',
|
||||||
{
|
{
|
||||||
link_id: 'link123',
|
link_id: 1,
|
||||||
issue_id: undefined,
|
|
||||||
conversation_id: undefined,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('creates a valid request with all parameters', () => {
|
|
||||||
LinearAPIClient.unlinkIssue('link123', 'ENG-456', 789);
|
|
||||||
expect(axiosMock.post).toHaveBeenCalledWith(
|
|
||||||
'/api/v1/integrations/linear/unlink_issue',
|
|
||||||
{
|
|
||||||
link_id: 'link123',
|
|
||||||
issue_id: 'ENG-456',
|
|
||||||
conversation_id: 789,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
@apply max-w-full;
|
@apply max-w-full;
|
||||||
|
|
||||||
.multiselect__option {
|
.multiselect__option {
|
||||||
@apply text-sm font-normal flex justify-between items-center;
|
@apply text-sm font-normal;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
@apply inline-block overflow-hidden text-ellipsis whitespace-nowrap w-fit;
|
@apply inline-block overflow-hidden text-ellipsis whitespace-nowrap w-fit;
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
@apply bottom-0 flex items-center justify-center text-center relative px-1 leading-tight;
|
@apply bottom-0 flex items-center justify-center text-center;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.multiselect__option--highlight {
|
&.multiselect__option--highlight {
|
||||||
@@ -74,7 +74,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.multiselect__option--highlight::after {
|
&.multiselect__option--highlight::after {
|
||||||
@apply bg-transparent text-n-slate-12;
|
@apply bg-transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.multiselect__option--selected {
|
&.multiselect__option--selected {
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ const isConversationRoute = computed(() => {
|
|||||||
'conversation_through_mentions',
|
'conversation_through_mentions',
|
||||||
'conversation_through_unattended',
|
'conversation_through_unattended',
|
||||||
'conversation_through_participating',
|
'conversation_through_participating',
|
||||||
'inbox_view_conversation',
|
|
||||||
];
|
];
|
||||||
return CONVERSATION_ROUTES.includes(route.name);
|
return CONVERSATION_ROUTES.includes(route.name);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ const shouldRenderMessage = computed(() => {
|
|||||||
function openContextMenu(e) {
|
function openContextMenu(e) {
|
||||||
const shouldSkipContextMenu =
|
const shouldSkipContextMenu =
|
||||||
e.target?.classList.contains('skip-context-menu') ||
|
e.target?.classList.contains('skip-context-menu') ||
|
||||||
['a', 'img'].includes(e.target?.tagName.toLowerCase());
|
e.target?.tagName.toLowerCase() === 'a';
|
||||||
if (shouldSkipContextMenu || getSelection().toString()) {
|
if (shouldSkipContextMenu || getSelection().toString()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ const fromEmail = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const toEmail = computed(() => {
|
const toEmail = computed(() => {
|
||||||
const { toEmails, email } = contentAttributes.value;
|
return contentAttributes.value?.email?.to ?? [];
|
||||||
return email?.to ?? toEmails ?? [];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const ccEmail = computed(() => {
|
const ccEmail = computed(() => {
|
||||||
|
|||||||
@@ -756,7 +756,6 @@ function toggleSelectAll(check) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEmitter('fetch_conversation_stats', () => {
|
useEmitter('fetch_conversation_stats', () => {
|
||||||
if (hasAppliedFiltersOrActiveFolders.value) return;
|
|
||||||
store.dispatch('conversationStats/get', conversationFilters.value);
|
store.dispatch('conversationStats/get', conversationFilters.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -855,7 +854,7 @@ watch(conversationFilters, (newVal, oldVal) => {
|
|||||||
:active-status="activeStatus"
|
:active-status="activeStatus"
|
||||||
:is-on-expanded-layout="isOnExpandedLayout"
|
:is-on-expanded-layout="isOnExpandedLayout"
|
||||||
:conversation-stats="conversationStats"
|
:conversation-stats="conversationStats"
|
||||||
:is-list-loading="chatListLoading && !conversationList.length"
|
:is-list-loading="chatListLoading"
|
||||||
@add-folders="onClickOpenAddFoldersModal"
|
@add-folders="onClickOpenAddFoldersModal"
|
||||||
@delete-folders="onClickOpenDeleteFoldersModal"
|
@delete-folders="onClickOpenDeleteFoldersModal"
|
||||||
@filters-modal="onToggleAdvanceFiltersModal"
|
@filters-modal="onToggleAdvanceFiltersModal"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ const props = defineProps({
|
|||||||
const isRelaxed = computed(() => props.type === 'relaxed');
|
const isRelaxed = computed(() => props.type === 'relaxed');
|
||||||
const headerClass = computed(() =>
|
const headerClass = computed(() =>
|
||||||
isRelaxed.value
|
isRelaxed.value
|
||||||
? 'ltr:first:rounded-bl-lg ltr:first:rounded-tl-lg ltr:last:rounded-br-lg ltr:last:rounded-tr-lg rtl:first:rounded-br-lg rtl:first:rounded-tr-lg rtl:last:rounded-bl-lg rtl:last:rounded-tl-lg'
|
? 'first:rounded-bl-lg first:rounded-tl-lg last:rounded-br-lg last:rounded-tr-lg'
|
||||||
: ''
|
: ''
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -183,18 +183,13 @@ const createIssue = async () => {
|
|||||||
state_id: formState.stateId || undefined,
|
state_id: formState.stateId || undefined,
|
||||||
priority: formState.priority || undefined,
|
priority: formState.priority || undefined,
|
||||||
label_ids: formState.labelId ? [formState.labelId] : undefined,
|
label_ids: formState.labelId ? [formState.labelId] : undefined,
|
||||||
conversation_id: props.conversationId,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
isCreating.value = true;
|
isCreating.value = true;
|
||||||
const response = await LinearAPI.createIssue(payload);
|
const response = await LinearAPI.createIssue(payload);
|
||||||
const { identifier: issueIdentifier } = response.data;
|
const { id: issueId } = response.data;
|
||||||
await LinearAPI.link_issue(
|
await LinearAPI.link_issue(props.conversationId, issueId, props.title);
|
||||||
props.conversationId,
|
|
||||||
issueIdentifier,
|
|
||||||
props.title
|
|
||||||
);
|
|
||||||
useAlert(t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.CREATE_SUCCESS'));
|
useAlert(t('INTEGRATION_SETTINGS.LINEAR.ADD_OR_LINK.CREATE_SUCCESS'));
|
||||||
useTrack(LINEAR_EVENTS.CREATE_ISSUE);
|
useTrack(LINEAR_EVENTS.CREATE_ISSUE);
|
||||||
onClose();
|
onClose();
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ const loadLinkedIssues = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const unlinkIssue = async (linkId, issueIdentifier) => {
|
const unlinkIssue = async linkId => {
|
||||||
try {
|
try {
|
||||||
await LinearAPI.unlinkIssue(linkId, issueIdentifier, props.conversationId);
|
await LinearAPI.unlinkIssue(linkId);
|
||||||
useTrack(LINEAR_EVENTS.UNLINK_ISSUE);
|
useTrack(LINEAR_EVENTS.UNLINK_ISSUE);
|
||||||
linkedIssues.value = linkedIssues.value.filter(
|
linkedIssues.value = linkedIssues.value.filter(
|
||||||
issue => issue.id !== linkId
|
issue => issue.id !== linkId
|
||||||
@@ -110,7 +110,7 @@ onMounted(() => {
|
|||||||
<LinearIssueItem
|
<LinearIssueItem
|
||||||
v-for="linkedIssue in linkedIssues"
|
v-for="linkedIssue in linkedIssues"
|
||||||
:key="linkedIssue.id"
|
:key="linkedIssue.id"
|
||||||
class="px-4 pt-3 pb-4 border-b border-n-weak last:border-b-0"
|
class="pt-3 px-4 pb-4 border-b border-n-weak last:border-b-0"
|
||||||
:linked-issue="linkedIssue"
|
:linked-issue="linkedIssue"
|
||||||
@unlink-issue="unlinkIssue"
|
@unlink-issue="unlinkIssue"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ const props = defineProps({
|
|||||||
|
|
||||||
const emit = defineEmits(['unlinkIssue']);
|
const emit = defineEmits(['unlinkIssue']);
|
||||||
|
|
||||||
const { linkedIssue } = props;
|
|
||||||
|
|
||||||
const priorityMap = {
|
const priorityMap = {
|
||||||
1: 'Urgent',
|
1: 'Urgent',
|
||||||
2: 'High',
|
2: 'High',
|
||||||
@@ -23,7 +21,7 @@ const priorityMap = {
|
|||||||
4: 'Low',
|
4: 'Low',
|
||||||
};
|
};
|
||||||
|
|
||||||
const issue = computed(() => linkedIssue.issue);
|
const issue = computed(() => props.linkedIssue.issue);
|
||||||
|
|
||||||
const assignee = computed(() => {
|
const assignee = computed(() => {
|
||||||
const assigneeDetails = issue.value.assignee;
|
const assigneeDetails = issue.value.assignee;
|
||||||
@@ -39,7 +37,7 @@ const labels = computed(() => issue.value.labels?.nodes || []);
|
|||||||
const priorityLabel = computed(() => priorityMap[issue.value.priority]);
|
const priorityLabel = computed(() => priorityMap[issue.value.priority]);
|
||||||
|
|
||||||
const unlinkIssue = () => {
|
const unlinkIssue = () => {
|
||||||
emit('unlinkIssue', linkedIssue.id, linkedIssue.issue.identifier);
|
emit('unlinkIssue', props.linkedIssue.id);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const onSearch = async value => {
|
|||||||
isFetching.value = true;
|
isFetching.value = true;
|
||||||
const response = await LinearAPI.searchIssues(value);
|
const response = await LinearAPI.searchIssues(value);
|
||||||
issues.value = response.data.map(issue => ({
|
issues.value = response.data.map(issue => ({
|
||||||
id: issue.identifier,
|
id: issue.id,
|
||||||
name: `${issue.identifier} ${issue.title}`,
|
name: `${issue.identifier} ${issue.title}`,
|
||||||
icon: 'status',
|
icon: 'status',
|
||||||
iconColor: issue.state.color,
|
iconColor: issue.state.color,
|
||||||
|
|||||||
@@ -329,12 +329,26 @@
|
|||||||
"BUTTON_TEXT": "Connect Linear workspace"
|
"BUTTON_TEXT": "Connect Linear workspace"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"NOTION": {
|
"GITHUB": {
|
||||||
"DELETE": {
|
"TITLE": "GitHub Integration",
|
||||||
"TITLE": "Are you sure you want to delete the Notion integration?",
|
"DESCRIPTION": "Connect your GitHub repositories to create issues directly from customer conversations. This integration helps you track bugs, feature requests, and development tasks seamlessly.",
|
||||||
"MESSAGE": "Deleting this integration will remove access to your Notion workspace and stop all related functionality.",
|
"NOT_CONFIGURED": {
|
||||||
"CONFIRM": "Yes, delete",
|
"TITLE": "GitHub Integration Not Configured",
|
||||||
"CANCEL": "Cancel"
|
"DESCRIPTION": "Contact your administrator to configure GitHub OAuth settings."
|
||||||
|
},
|
||||||
|
"CONNECT": {
|
||||||
|
"TITLE": "Connect GitHub",
|
||||||
|
"DESCRIPTION": "Connect your GitHub account to start creating issues from conversations.",
|
||||||
|
"BUTTON": "Connect GitHub"
|
||||||
|
},
|
||||||
|
"CONNECTED": {
|
||||||
|
"TITLE": "GitHub Connected",
|
||||||
|
"DESCRIPTION": "Your GitHub account is successfully connected. You can now create issues from conversations."
|
||||||
|
},
|
||||||
|
"DISCONNECT": {
|
||||||
|
"BUTTON": "Disconnect",
|
||||||
|
"SUCCESS": "GitHub integration disconnected successfully",
|
||||||
|
"ERROR": "Failed to disconnect GitHub integration"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -152,7 +152,7 @@
|
|||||||
"ATTRIBUTES": {
|
"ATTRIBUTES": {
|
||||||
"MESSAGE_TYPE": "Tipo da Mensagem",
|
"MESSAGE_TYPE": "Tipo da Mensagem",
|
||||||
"MESSAGE_CONTAINS": "A mensagem contém",
|
"MESSAGE_CONTAINS": "A mensagem contém",
|
||||||
"EMAIL": "E-mail",
|
"EMAIL": "e-mail",
|
||||||
"INBOX": "Caixa de Entrada",
|
"INBOX": "Caixa de Entrada",
|
||||||
"CONVERSATION_LANGUAGE": "Idioma da conversa",
|
"CONVERSATION_LANGUAGE": "Idioma da conversa",
|
||||||
"PHONE_NUMBER": "Número de Telefone",
|
"PHONE_NUMBER": "Número de Telefone",
|
||||||
|
|||||||
@@ -130,15 +130,15 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex multiselect-wrap--medium">
|
<div class="flex multiselect-wrap--medium">
|
||||||
<div
|
<div
|
||||||
class="w-8 relative text-base text-slate-100 dark:text-slate-600 after:content-[''] after:h-12 after:w-0 ltr:after:left-4 rtl:after:right-4 after:absolute after:border-l after:border-solid after:border-slate-100 after:dark:border-slate-600 before:content-[''] before:h-0 before:w-4 ltr:before:left-4 rtl:before:right-4 before:top-12 before:absolute before:border-b before:border-solid before:border-slate-100 before:dark:border-slate-600"
|
class="w-8 relative text-base text-slate-100 dark:text-slate-600 after:content-[''] after:h-12 after:w-0 after:left-4 after:absolute after:border-l after:border-solid after:border-slate-100 after:dark:border-slate-600 before:content-[''] before:h-0 before:w-4 before:left-4 before:top-12 before:absolute before:border-b before:border-solid before:border-slate-100 before:dark:border-slate-600"
|
||||||
>
|
>
|
||||||
<fluent-icon
|
<fluent-icon
|
||||||
icon="arrow-up"
|
icon="arrow-up"
|
||||||
class="absolute -top-1 ltr:left-2 rtl:right-2"
|
class="absolute -top-1 left-2"
|
||||||
size="17"
|
size="17"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col w-full ltr:pl-8 rtl:pr-8">
|
<div class="flex flex-col w-full">
|
||||||
<label class="multiselect__label">
|
<label class="multiselect__label">
|
||||||
{{ $t('MERGE_CONTACTS.PRIMARY.TITLE') }}
|
{{ $t('MERGE_CONTACTS.PRIMARY.TITLE') }}
|
||||||
<woot-label
|
<woot-label
|
||||||
|
|||||||
@@ -71,12 +71,6 @@ export default {
|
|||||||
FEATURE_FLAGS.AUTO_RESOLVE_CONVERSATIONS
|
FEATURE_FLAGS.AUTO_RESOLVE_CONVERSATIONS
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
showAudioTranscriptionConfig() {
|
|
||||||
return this.isFeatureEnabledonAccount(
|
|
||||||
this.accountId,
|
|
||||||
FEATURE_FLAGS.CAPTAIN
|
|
||||||
);
|
|
||||||
},
|
|
||||||
languagesSortedByCode() {
|
languagesSortedByCode() {
|
||||||
const enabledLanguages = [...this.enabledLanguages];
|
const enabledLanguages = [...this.enabledLanguages];
|
||||||
return enabledLanguages.sort((l1, l2) =>
|
return enabledLanguages.sort((l1, l2) =>
|
||||||
@@ -243,7 +237,7 @@ export default {
|
|||||||
<woot-loading-state v-if="uiFlags.isFetchingItem" />
|
<woot-loading-state v-if="uiFlags.isFetchingItem" />
|
||||||
</div>
|
</div>
|
||||||
<AutoResolve v-if="showAutoResolutionConfig" />
|
<AutoResolve v-if="showAutoResolutionConfig" />
|
||||||
<AudioTranscription v-if="showAudioTranscriptionConfig" />
|
<AudioTranscription v-if="isOnChatwootCloud" />
|
||||||
<AccountId />
|
<AccountId />
|
||||||
<div v-if="!uiFlags.isFetchingItem && isOnChatwootCloud">
|
<div v-if="!uiFlags.isFetchingItem && isOnChatwootCloud">
|
||||||
<AccountDelete />
|
<AccountDelete />
|
||||||
|
|||||||
+1
@@ -12,6 +12,7 @@ defineOptions({
|
|||||||
provider="google"
|
provider="google"
|
||||||
:title="$t('INBOX_MGMT.ADD.GOOGLE.TITLE')"
|
:title="$t('INBOX_MGMT.ADD.GOOGLE.TITLE')"
|
||||||
:description="$t('INBOX_MGMT.ADD.GOOGLE.DESCRIPTION')"
|
:description="$t('INBOX_MGMT.ADD.GOOGLE.DESCRIPTION')"
|
||||||
|
:input-placeholder="$t('INBOX_MGMT.ADD.GOOGLE.EMAIL_PLACEHOLDER')"
|
||||||
:submit-button-text="$t('INBOX_MGMT.ADD.GOOGLE.SIGN_IN')"
|
:submit-button-text="$t('INBOX_MGMT.ADD.GOOGLE.SIGN_IN')"
|
||||||
:error-message="$t('INBOX_MGMT.ADD.GOOGLE.ERROR_MESSAGE')"
|
:error-message="$t('INBOX_MGMT.ADD.GOOGLE.ERROR_MESSAGE')"
|
||||||
/>
|
/>
|
||||||
|
|||||||
+1
@@ -12,6 +12,7 @@ defineOptions({
|
|||||||
provider="microsoft"
|
provider="microsoft"
|
||||||
:title="$t('INBOX_MGMT.ADD.MICROSOFT.TITLE')"
|
:title="$t('INBOX_MGMT.ADD.MICROSOFT.TITLE')"
|
||||||
:description="$t('INBOX_MGMT.ADD.MICROSOFT.DESCRIPTION')"
|
:description="$t('INBOX_MGMT.ADD.MICROSOFT.DESCRIPTION')"
|
||||||
|
:input-placeholder="$t('INBOX_MGMT.ADD.MICROSOFT.EMAIL_PLACEHOLDER')"
|
||||||
:submit-button-text="$t('INBOX_MGMT.ADD.MICROSOFT.SIGN_IN')"
|
:submit-button-text="$t('INBOX_MGMT.ADD.MICROSOFT.SIGN_IN')"
|
||||||
:error-message="$t('INBOX_MGMT.ADD.MICROSOFT.ERROR_MESSAGE')"
|
:error-message="$t('INBOX_MGMT.ADD.MICROSOFT.ERROR_MESSAGE')"
|
||||||
/>
|
/>
|
||||||
|
|||||||
+13
-1
@@ -30,9 +30,14 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
inputPlaceholder: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const isRequestingAuthorization = ref(false);
|
const isRequestingAuthorization = ref(false);
|
||||||
|
const email = ref('');
|
||||||
|
|
||||||
const client = computed(() => {
|
const client = computed(() => {
|
||||||
if (props.provider === 'microsoft') {
|
if (props.provider === 'microsoft') {
|
||||||
@@ -45,7 +50,9 @@ const client = computed(() => {
|
|||||||
async function requestAuthorization() {
|
async function requestAuthorization() {
|
||||||
try {
|
try {
|
||||||
isRequestingAuthorization.value = true;
|
isRequestingAuthorization.value = true;
|
||||||
const response = await client.value.generateAuthorization();
|
const response = await client.value.generateAuthorization({
|
||||||
|
email: email.value,
|
||||||
|
});
|
||||||
const {
|
const {
|
||||||
data: { url },
|
data: { url },
|
||||||
} = response;
|
} = response;
|
||||||
@@ -68,6 +75,11 @@ async function requestAuthorization() {
|
|||||||
:header-content="description"
|
:header-content="description"
|
||||||
/>
|
/>
|
||||||
<form class="mt-6" @submit.prevent="requestAuthorization">
|
<form class="mt-6" @submit.prevent="requestAuthorization">
|
||||||
|
<woot-input
|
||||||
|
v-model="email"
|
||||||
|
type="email"
|
||||||
|
:placeholder="inputPlaceholder"
|
||||||
|
/>
|
||||||
<NextButton
|
<NextButton
|
||||||
:is-loading="isRequestingAuthorization"
|
:is-loading="isRequestingAuthorization"
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|||||||
+11
-34
@@ -5,19 +5,15 @@ import {
|
|||||||
useMapGetter,
|
useMapGetter,
|
||||||
useStore,
|
useStore,
|
||||||
} from 'dashboard/composables/store';
|
} from 'dashboard/composables/store';
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
|
|
||||||
import ButtonNext from 'next/button/Button.vue';
|
|
||||||
import notionClient from 'dashboard/api/notion_auth.js';
|
|
||||||
|
|
||||||
import Integration from './Integration.vue';
|
import Integration from './Integration.vue';
|
||||||
import Spinner from 'shared/components/Spinner.vue';
|
import Spinner from 'shared/components/Spinner.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
|
||||||
const integrationLoaded = ref(false);
|
const integrationLoaded = ref(false);
|
||||||
|
|
||||||
const integration = useFunctionGetter('integrations/getIntegration', 'notion');
|
const integration = useFunctionGetter('integrations/getIntegration', 'github');
|
||||||
|
|
||||||
const uiFlags = useMapGetter('integrations/getUIFlags');
|
const uiFlags = useMapGetter('integrations/getUIFlags');
|
||||||
|
|
||||||
@@ -25,32 +21,22 @@ const integrationAction = computed(() => {
|
|||||||
if (integration.value.enabled) {
|
if (integration.value.enabled) {
|
||||||
return 'disconnect';
|
return 'disconnect';
|
||||||
}
|
}
|
||||||
|
return integration.value.action;
|
||||||
return '';
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const authorize = async () => {
|
const initializeGithubIntegration = async () => {
|
||||||
const response = await notionClient.generateAuthorization();
|
await store.dispatch('integrations/get', 'github');
|
||||||
const {
|
|
||||||
data: { url },
|
|
||||||
} = response;
|
|
||||||
|
|
||||||
window.location.href = url;
|
|
||||||
};
|
|
||||||
|
|
||||||
const initializeNotionIntegration = async () => {
|
|
||||||
await store.dispatch('integrations/get', 'notion');
|
|
||||||
integrationLoaded.value = true;
|
integrationLoaded.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initializeNotionIntegration();
|
initializeGithubIntegration();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex-grow flex-shrink p-4 overflow-auto mx-auto">
|
<div class="flex-grow flex-shrink max-w-6xl p-4 mx-auto overflow-auto">
|
||||||
<div v-if="integrationLoaded && !uiFlags.isCreatingNotion">
|
<div v-if="integrationLoaded && !uiFlags.isCreatingGithub">
|
||||||
<Integration
|
<Integration
|
||||||
:integration-id="integration.id"
|
:integration-id="integration.id"
|
||||||
:integration-logo="integration.logo"
|
:integration-logo="integration.logo"
|
||||||
@@ -59,19 +45,10 @@ onMounted(() => {
|
|||||||
:integration-enabled="integration.enabled"
|
:integration-enabled="integration.enabled"
|
||||||
:integration-action="integrationAction"
|
:integration-action="integrationAction"
|
||||||
:delete-confirmation-text="{
|
:delete-confirmation-text="{
|
||||||
title: t('INTEGRATION_SETTINGS.NOTION.DELETE.TITLE'),
|
title: $t('INTEGRATION_SETTINGS.GITHUB.DELETE.TITLE'),
|
||||||
message: t('INTEGRATION_SETTINGS.NOTION.DELETE.MESSAGE'),
|
message: $t('INTEGRATION_SETTINGS.GITHUB.DELETE.MESSAGE'),
|
||||||
}"
|
}"
|
||||||
>
|
/>
|
||||||
<template #action>
|
|
||||||
<ButtonNext
|
|
||||||
faded
|
|
||||||
blue
|
|
||||||
:label="t('INTEGRATION_SETTINGS.CONNECT.BUTTON_TEXT')"
|
|
||||||
@click="authorize"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</Integration>
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="flex items-center justify-center flex-1">
|
<div v-else class="flex items-center justify-center flex-1">
|
||||||
<Spinner size="" color-scheme="primary" />
|
<Spinner size="" color-scheme="primary" />
|
||||||
+9
-10
@@ -8,8 +8,8 @@ import DashboardApps from './DashboardApps/Index.vue';
|
|||||||
import Slack from './Slack.vue';
|
import Slack from './Slack.vue';
|
||||||
import SettingsContent from '../Wrapper.vue';
|
import SettingsContent from '../Wrapper.vue';
|
||||||
import Linear from './Linear.vue';
|
import Linear from './Linear.vue';
|
||||||
import Notion from './Notion.vue';
|
|
||||||
import Shopify from './Shopify.vue';
|
import Shopify from './Shopify.vue';
|
||||||
|
import Github from './Github.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
routes: [
|
routes: [
|
||||||
@@ -91,15 +91,6 @@ export default {
|
|||||||
},
|
},
|
||||||
props: route => ({ code: route.query.code }),
|
props: route => ({ code: route.query.code }),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'notion',
|
|
||||||
name: 'settings_integrations_notion',
|
|
||||||
component: Notion,
|
|
||||||
meta: {
|
|
||||||
permissions: ['administrator'],
|
|
||||||
},
|
|
||||||
props: route => ({ code: route.query.code }),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'shopify',
|
path: 'shopify',
|
||||||
name: 'settings_integrations_shopify',
|
name: 'settings_integrations_shopify',
|
||||||
@@ -110,6 +101,14 @@ export default {
|
|||||||
},
|
},
|
||||||
props: route => ({ error: route.query.error }),
|
props: route => ({ error: route.query.error }),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'github',
|
||||||
|
name: 'settings_integrations_github',
|
||||||
|
component: Github,
|
||||||
|
meta: {
|
||||||
|
permissions: ['administrator'],
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: ':integration_id',
|
path: ':integration_id',
|
||||||
name: 'settings_applications_integration',
|
name: 'settings_applications_integration',
|
||||||
|
|||||||
+4
-28
@@ -75,34 +75,10 @@ export default {
|
|||||||
onRegistrationSuccess() {
|
onRegistrationSuccess() {
|
||||||
this.hasEnabledPushPermissions = true;
|
this.hasEnabledPushPermissions = true;
|
||||||
},
|
},
|
||||||
onRequestPermissions(value) {
|
onRequestPermissions() {
|
||||||
if (value) {
|
requestPushPermissions({
|
||||||
// Enable / re-enable push notifications
|
onSuccess: this.onRegistrationSuccess,
|
||||||
requestPushPermissions({
|
});
|
||||||
onSuccess: this.onRegistrationSuccess,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Disable push notifications
|
|
||||||
this.disablePushPermissions();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
disablePushPermissions() {
|
|
||||||
verifyServiceWorkerExistence(registration =>
|
|
||||||
registration.pushManager
|
|
||||||
.getSubscription()
|
|
||||||
.then(subscription => {
|
|
||||||
if (subscription) {
|
|
||||||
return subscription.unsubscribe();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.hasEnabledPushPermissions = false;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
// error
|
|
||||||
})
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
getPushSubscription() {
|
getPushSubscription() {
|
||||||
verifyServiceWorkerExistence(registration =>
|
verifyServiceWorkerExistence(registration =>
|
||||||
|
|||||||
+3
-5
@@ -59,7 +59,7 @@ const defaulSpanRender = cellProps =>
|
|||||||
cellProps.getValue()
|
cellProps.getValue()
|
||||||
);
|
);
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = [
|
||||||
columnHelper.accessor('name', {
|
columnHelper.accessor('name', {
|
||||||
header: t(`SUMMARY_REPORTS.${props.type.toUpperCase()}`),
|
header: t(`SUMMARY_REPORTS.${props.type.toUpperCase()}`),
|
||||||
width: 300,
|
width: 300,
|
||||||
@@ -90,7 +90,7 @@ const columns = computed(() => [
|
|||||||
width: 200,
|
width: 200,
|
||||||
cell: defaulSpanRender,
|
cell: defaulSpanRender,
|
||||||
}),
|
}),
|
||||||
]);
|
];
|
||||||
|
|
||||||
const renderAvgTime = value => (value ? formatTime(value) : '--');
|
const renderAvgTime = value => (value ? formatTime(value) : '--');
|
||||||
|
|
||||||
@@ -142,9 +142,7 @@ const table = useVueTable({
|
|||||||
get data() {
|
get data() {
|
||||||
return tableData.value;
|
return tableData.value;
|
||||||
},
|
},
|
||||||
get columns() {
|
columns,
|
||||||
return columns.value;
|
|
||||||
},
|
|
||||||
enableSorting: false,
|
enableSorting: false,
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class Webhooks::TelegramEventsJob < ApplicationJob
|
|||||||
def process_event_params(channel, params)
|
def process_event_params(channel, params)
|
||||||
return unless params[:telegram]
|
return unless params[:telegram]
|
||||||
|
|
||||||
if params.dig(:telegram, :edited_message).present? || params.dig(:telegram, :edited_business_message).present?
|
if params.dig(:telegram, :edited_message).present?
|
||||||
Telegram::UpdateMessageService.new(inbox: channel.inbox, params: params['telegram'].with_indifferent_access).perform
|
Telegram::UpdateMessageService.new(inbox: channel.inbox, params: params['telegram'].with_indifferent_access).perform
|
||||||
else
|
else
|
||||||
Telegram::IncomingMessageService.new(inbox: channel.inbox, params: params['telegram'].with_indifferent_access).perform
|
Telegram::IncomingMessageService.new(inbox: channel.inbox, params: params['telegram'].with_indifferent_access).perform
|
||||||
|
|||||||
@@ -69,10 +69,6 @@ class Channel::Telegram < ApplicationRecord
|
|||||||
message.conversation[:additional_attributes]['chat_id']
|
message.conversation[:additional_attributes]['chat_id']
|
||||||
end
|
end
|
||||||
|
|
||||||
def business_connection_id(message)
|
|
||||||
message.conversation[:additional_attributes]['business_connection_id']
|
|
||||||
end
|
|
||||||
|
|
||||||
def reply_to_message_id(message)
|
def reply_to_message_id(message)
|
||||||
message.content_attributes['in_reply_to_external_id']
|
message.content_attributes['in_reply_to_external_id']
|
||||||
end
|
end
|
||||||
@@ -99,13 +95,7 @@ class Channel::Telegram < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def send_message(message)
|
def send_message(message)
|
||||||
response = message_request(
|
response = message_request(chat_id(message), message.outgoing_content, reply_markup(message), reply_to_message_id(message))
|
||||||
chat_id(message),
|
|
||||||
message.outgoing_content,
|
|
||||||
reply_markup(message),
|
|
||||||
reply_to_message_id(message),
|
|
||||||
business_connection_id: business_connection_id(message)
|
|
||||||
)
|
|
||||||
process_error(message, response)
|
process_error(message, response)
|
||||||
response.parsed_response['result']['message_id'] if response.success?
|
response.parsed_response['result']['message_id'] if response.success?
|
||||||
end
|
end
|
||||||
@@ -141,12 +131,9 @@ class Channel::Telegram < ApplicationRecord
|
|||||||
stripped_html.gsub('<br>', "\n")
|
stripped_html.gsub('<br>', "\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
def message_request(chat_id, text, reply_markup = nil, reply_to_message_id = nil, business_connection_id: nil)
|
def message_request(chat_id, text, reply_markup = nil, reply_to_message_id = nil)
|
||||||
text_payload = convert_markdown_to_telegram_html(text)
|
text_payload = convert_markdown_to_telegram_html(text)
|
||||||
|
|
||||||
business_body = {}
|
|
||||||
business_body[:business_connection_id] = business_connection_id if business_connection_id
|
|
||||||
|
|
||||||
HTTParty.post("#{telegram_api_url}/sendMessage",
|
HTTParty.post("#{telegram_api_url}/sendMessage",
|
||||||
body: {
|
body: {
|
||||||
chat_id: chat_id,
|
chat_id: chat_id,
|
||||||
@@ -154,6 +141,6 @@ class Channel::Telegram < ApplicationRecord
|
|||||||
reply_markup: reply_markup,
|
reply_markup: reply_markup,
|
||||||
parse_mode: 'HTML',
|
parse_mode: 'HTML',
|
||||||
reply_to_message_id: reply_to_message_id
|
reply_to_message_id: reply_to_message_id
|
||||||
}.merge(business_body))
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ class Integrations::App
|
|||||||
"#{params[:action]}&client_id=#{client_id}&redirect_uri=#{self.class.slack_integration_url}"
|
"#{params[:action]}&client_id=#{client_id}&redirect_uri=#{self.class.slack_integration_url}"
|
||||||
when 'linear'
|
when 'linear'
|
||||||
build_linear_action
|
build_linear_action
|
||||||
|
when 'github'
|
||||||
|
build_github_action
|
||||||
else
|
else
|
||||||
params[:action]
|
params[:action]
|
||||||
end
|
end
|
||||||
@@ -58,8 +60,8 @@ class Integrations::App
|
|||||||
account.feature_enabled?('shopify_integration') && GlobalConfigService.load('SHOPIFY_CLIENT_ID', nil).present?
|
account.feature_enabled?('shopify_integration') && GlobalConfigService.load('SHOPIFY_CLIENT_ID', nil).present?
|
||||||
when 'leadsquared'
|
when 'leadsquared'
|
||||||
account.feature_enabled?('crm_integration')
|
account.feature_enabled?('crm_integration')
|
||||||
when 'notion'
|
when 'github'
|
||||||
account.feature_enabled?('notion_integration') && GlobalConfigService.load('NOTION_CLIENT_ID', nil).present?
|
GlobalConfigService.load('GITHUB_CLIENT_ID', nil).present?
|
||||||
else
|
else
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
@@ -77,6 +79,16 @@ class Integrations::App
|
|||||||
].join('&')
|
].join('&')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def build_github_action
|
||||||
|
client_id = GlobalConfigService.load('GITHUB_CLIENT_ID', nil)
|
||||||
|
[
|
||||||
|
'https://github.com/login/oauth/authorize?response_type=code',
|
||||||
|
"client_id=#{client_id}",
|
||||||
|
"redirect_uri=#{self.class.github_integration_url}",
|
||||||
|
'scope=repo'
|
||||||
|
].join('&')
|
||||||
|
end
|
||||||
|
|
||||||
def enabled?(account)
|
def enabled?(account)
|
||||||
case params[:id]
|
case params[:id]
|
||||||
when 'webhook'
|
when 'webhook'
|
||||||
@@ -100,6 +112,10 @@ class Integrations::App
|
|||||||
"#{ENV.fetch('FRONTEND_URL', nil)}/linear/callback"
|
"#{ENV.fetch('FRONTEND_URL', nil)}/linear/callback"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.github_integration_url
|
||||||
|
"#{ENV.fetch('FRONTEND_URL', nil)}/github/callback"
|
||||||
|
end
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def apps
|
def apps
|
||||||
Hashie::Mash.new(APPS_CONFIG)
|
Hashie::Mash.new(APPS_CONFIG)
|
||||||
|
|||||||
@@ -53,10 +53,6 @@ class Integrations::Hook < ApplicationRecord
|
|||||||
app_id == 'dialogflow'
|
app_id == 'dialogflow'
|
||||||
end
|
end
|
||||||
|
|
||||||
def notion?
|
|
||||||
app_id == 'notion'
|
|
||||||
end
|
|
||||||
|
|
||||||
def disable
|
def disable
|
||||||
update(status: 'disabled')
|
update(status: 'disabled')
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
class NotionPagePresenter
|
|
||||||
def initialize(page_response, blocks_response)
|
|
||||||
@page_response = page_response
|
|
||||||
@blocks_response = blocks_response
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_hash
|
|
||||||
{
|
|
||||||
'id' => @page_response['id'],
|
|
||||||
'icon' => @page_response['icon'],
|
|
||||||
'title' => extract_page_title,
|
|
||||||
'url' => @page_response['url'],
|
|
||||||
'created_time' => @page_response['created_time'],
|
|
||||||
'last_edited_time' => @page_response['last_edited_time'],
|
|
||||||
'md' => generate_markdown,
|
|
||||||
'child_pages' => extract_child_pages
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def extract_page_title
|
|
||||||
# Try to get title from properties (for database pages)
|
|
||||||
if @page_response['properties']
|
|
||||||
title_property = @page_response['properties'].values.find { |prop| prop['type'] == 'title' }
|
|
||||||
return title_property['title'].map { |t| t['plain_text'] }.join if title_property && title_property['title']&.any?
|
|
||||||
end
|
|
||||||
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_markdown
|
|
||||||
title = extract_page_title
|
|
||||||
content_md = NotionToMarkdown.new.convert(@blocks_response['results'])
|
|
||||||
title_md = title ? "# #{title}\n\n" : ''
|
|
||||||
|
|
||||||
"#{title_md}#{content_md}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def extract_child_pages
|
|
||||||
extract_child_pages_from_blocks(@blocks_response['results'])
|
|
||||||
end
|
|
||||||
|
|
||||||
def extract_child_pages_from_blocks(blocks)
|
|
||||||
child_pages = []
|
|
||||||
|
|
||||||
blocks.each do |block|
|
|
||||||
if block['type'] == 'child_page'
|
|
||||||
child_pages << {
|
|
||||||
'id' => block['id'],
|
|
||||||
'title' => block['child_page']['title']
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
# Recursively check nested blocks
|
|
||||||
child_pages.concat(extract_child_pages_from_blocks(block['children'])) if block['has_children'] && block['children']
|
|
||||||
end
|
|
||||||
|
|
||||||
child_pages
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -24,15 +24,6 @@ class Instagram::Messenger::MessageText < Instagram::BaseMessageText
|
|||||||
end
|
end
|
||||||
|
|
||||||
def handle_client_error(error)
|
def handle_client_error(error)
|
||||||
# Handle error code 230: User consent is required to access user profile
|
|
||||||
# This typically occurs when the connected Instagram account attempts to send a message to a user
|
|
||||||
# who has never messaged this Instagram account before.
|
|
||||||
# We can safely ignore this error as per Facebook documentation.
|
|
||||||
if error.message.include?('230')
|
|
||||||
Rails.logger.warn error
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
Rails.logger.warn("[FacebookUserFetchClientError]: account_id #{@inbox.account_id} inbox_id #{@inbox.id}")
|
Rails.logger.warn("[FacebookUserFetchClientError]: account_id #{@inbox.account_id} inbox_id #{@inbox.id}")
|
||||||
Rails.logger.warn("[FacebookUserFetchClientError]: #{error.message}")
|
Rails.logger.warn("[FacebookUserFetchClientError]: #{error.message}")
|
||||||
ChatwootExceptionTracker.new(error, account: @inbox.account).capture_exception
|
ChatwootExceptionTracker.new(error, account: @inbox.account).capture_exception
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
class Linear::ActivityMessageService
|
|
||||||
attr_reader :conversation, :action_type, :issue_data, :user
|
|
||||||
|
|
||||||
def initialize(conversation:, action_type:, user:, issue_data: {})
|
|
||||||
@conversation = conversation
|
|
||||||
@action_type = action_type
|
|
||||||
@issue_data = issue_data
|
|
||||||
@user = user
|
|
||||||
end
|
|
||||||
|
|
||||||
def perform
|
|
||||||
return unless conversation && issue_data[:id] && user
|
|
||||||
|
|
||||||
content = generate_activity_content
|
|
||||||
return unless content
|
|
||||||
|
|
||||||
::Conversations::ActivityMessageJob.perform_later(conversation, activity_message_params(content))
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def generate_activity_content
|
|
||||||
case action_type.to_sym
|
|
||||||
when :issue_created
|
|
||||||
I18n.t('conversations.activity.linear.issue_created', user_name: user.name, issue_id: issue_data[:id])
|
|
||||||
when :issue_linked
|
|
||||||
I18n.t('conversations.activity.linear.issue_linked', user_name: user.name, issue_id: issue_data[:id])
|
|
||||||
when :issue_unlinked
|
|
||||||
I18n.t('conversations.activity.linear.issue_unlinked', user_name: user.name, issue_id: issue_data[:id])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def activity_message_params(content)
|
|
||||||
{
|
|
||||||
account_id: conversation.account_id,
|
|
||||||
inbox_id: conversation.inbox_id,
|
|
||||||
message_type: :activity,
|
|
||||||
content: content
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -11,13 +11,6 @@ class LlmFormatter::ConversationLlmFormatter < LlmFormatter::DefaultLlmFormatter
|
|||||||
end
|
end
|
||||||
|
|
||||||
sections << "Contact Details: #{@record.contact.to_llm_text}" if config[:include_contact_details]
|
sections << "Contact Details: #{@record.contact.to_llm_text}" if config[:include_contact_details]
|
||||||
|
|
||||||
attributes = build_attributes
|
|
||||||
if attributes.present?
|
|
||||||
sections << 'Conversation Attributes:'
|
|
||||||
sections << attributes
|
|
||||||
end
|
|
||||||
|
|
||||||
sections.join("\n")
|
sections.join("\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -37,11 +30,4 @@ class LlmFormatter::ConversationLlmFormatter < LlmFormatter::DefaultLlmFormatter
|
|||||||
sender = message.message_type == 'incoming' ? 'User' : 'Support agent'
|
sender = message.message_type == 'incoming' ? 'User' : 'Support agent'
|
||||||
"#{sender}: #{message.content}\n"
|
"#{sender}: #{message.content}\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_attributes
|
|
||||||
attributes = @record.account.custom_attribute_definitions.with_attribute_model('conversation_attribute').map do |attribute|
|
|
||||||
"#{attribute.attribute_display_name}: #{@record.custom_attributes[attribute.attribute_key]}"
|
|
||||||
end
|
|
||||||
attributes.join("\n")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ class MessageTemplates::Template::AutoResolve
|
|||||||
def perform
|
def perform
|
||||||
return if conversation.account.auto_resolve_message.blank?
|
return if conversation.account.auto_resolve_message.blank?
|
||||||
|
|
||||||
if within_messaging_window?
|
ActiveRecord::Base.transaction do
|
||||||
conversation.messages.create!(auto_resolve_message_params)
|
conversation.messages.create!(auto_resolve_message_params)
|
||||||
else
|
|
||||||
create_auto_resolve_not_sent_activity_message
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -16,21 +14,6 @@ class MessageTemplates::Template::AutoResolve
|
|||||||
delegate :contact, :account, to: :conversation
|
delegate :contact, :account, to: :conversation
|
||||||
delegate :inbox, to: :message
|
delegate :inbox, to: :message
|
||||||
|
|
||||||
def within_messaging_window?
|
|
||||||
conversation.can_reply?
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_auto_resolve_not_sent_activity_message
|
|
||||||
content = I18n.t('conversations.activity.auto_resolve.not_sent_due_to_messaging_window')
|
|
||||||
activity_message_params = {
|
|
||||||
account_id: conversation.account_id,
|
|
||||||
inbox_id: conversation.inbox_id,
|
|
||||||
message_type: :activity,
|
|
||||||
content: content
|
|
||||||
}
|
|
||||||
::Conversations::ActivityMessageJob.perform_later(conversation, activity_message_params) if content
|
|
||||||
end
|
|
||||||
|
|
||||||
def auto_resolve_message_params
|
def auto_resolve_message_params
|
||||||
{
|
{
|
||||||
account_id: @conversation.account_id,
|
account_id: @conversation.account_id,
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
class NotionToMarkdown
|
|
||||||
# Main entry: pass in the Notion page blocks (array of block hashes)
|
|
||||||
def convert(blocks)
|
|
||||||
blocks.map { |block| block_to_markdown(block) }.join("\n\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def block_to_markdown(block, depth = 0)
|
|
||||||
type = block['type']
|
|
||||||
return '' unless type
|
|
||||||
|
|
||||||
case type
|
|
||||||
when 'paragraph'
|
|
||||||
rich_text_to_md(block['paragraph']['rich_text'])
|
|
||||||
when 'heading_1'
|
|
||||||
"# #{rich_text_to_md(block['heading_1']['rich_text'])}"
|
|
||||||
when 'heading_2'
|
|
||||||
"## #{rich_text_to_md(block['heading_2']['rich_text'])}"
|
|
||||||
when 'heading_3'
|
|
||||||
"### #{rich_text_to_md(block['heading_3']['rich_text'])}"
|
|
||||||
when 'bulleted_list_item'
|
|
||||||
indent = ' ' * depth
|
|
||||||
"#{indent}- #{rich_text_to_md(block['bulleted_list_item']['rich_text'])}" +
|
|
||||||
children_to_md(block, depth + 1)
|
|
||||||
when 'numbered_list_item'
|
|
||||||
indent = ' ' * depth
|
|
||||||
"#{indent}1. #{rich_text_to_md(block['numbered_list_item']['rich_text'])}" +
|
|
||||||
children_to_md(block, depth + 1)
|
|
||||||
when 'to_do'
|
|
||||||
box = block['to_do']['checked'] ? '[x]' : '[ ]'
|
|
||||||
"- #{box} #{rich_text_to_md(block['to_do']['rich_text'])}"
|
|
||||||
when 'toggle'
|
|
||||||
summary = rich_text_to_md(block['toggle']['rich_text'])
|
|
||||||
details = children_to_md(block, depth + 1)
|
|
||||||
"<details>\n<summary>#{summary}</summary>\n\n#{details}\n</details>"
|
|
||||||
when 'quote'
|
|
||||||
quote = rich_text_to_md(block['quote']['rich_text'])
|
|
||||||
quote_lines = quote.lines.map { |line| "> #{line}" }.join
|
|
||||||
quote_lines + children_to_md(block, depth)
|
|
||||||
when 'code'
|
|
||||||
lang = block['code']['language'] || ''
|
|
||||||
code = block['code']['rich_text'].pluck('plain_text').join
|
|
||||||
"```#{lang}\n#{code}\n```"
|
|
||||||
when 'callout'
|
|
||||||
icon = block['callout']['icon']&.dig('emoji') || '💡'
|
|
||||||
content = rich_text_to_md(block['callout']['rich_text'])
|
|
||||||
"> [!#{icon}] #{content}" + children_to_md(block, depth + 1)
|
|
||||||
when 'divider'
|
|
||||||
'---'
|
|
||||||
when 'image'
|
|
||||||
url = block['image']['type'] == 'external' ? block['image']['external']['url'] : block['image']['file']['url']
|
|
||||||
caption = block['image']['caption']&.pluck('plain_text')&.join || 'image'
|
|
||||||
""
|
|
||||||
when 'bookmark'
|
|
||||||
url = block['bookmark']['url']
|
|
||||||
"[#{url}](#{url})"
|
|
||||||
when 'child_page'
|
|
||||||
"## #{block['child_page']['title']}" + children_to_md(block, depth + 1)
|
|
||||||
when 'table'
|
|
||||||
table_to_md(block)
|
|
||||||
else
|
|
||||||
'' # Add more block types as needed
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def children_to_md(block, depth)
|
|
||||||
return '' unless block['has_children'] && block['children']
|
|
||||||
|
|
||||||
"\n" + block['children'].map { |child| block_to_markdown(child, depth) }.join("\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def rich_text_to_md(rich_text_array)
|
|
||||||
return '' unless rich_text_array
|
|
||||||
|
|
||||||
rich_text_array.map { |t| annotate_text(t) }.join
|
|
||||||
end
|
|
||||||
|
|
||||||
def annotate_text(text_obj)
|
|
||||||
text = text_obj['plain_text']
|
|
||||||
ann = text_obj['annotations'] || {}
|
|
||||||
|
|
||||||
text = "**#{text}**" if ann['bold']
|
|
||||||
text = "*#{text}*" if ann['italic']
|
|
||||||
text = "~~#{text}~~" if ann['strikethrough']
|
|
||||||
text = "<u>#{text}</u>" if ann['underline']
|
|
||||||
text = "`#{text}`" if ann['code']
|
|
||||||
text = "[#{text}](#{text_obj['href']})" if text_obj['href']
|
|
||||||
text
|
|
||||||
end
|
|
||||||
|
|
||||||
def table_to_md(block)
|
|
||||||
rows = block['children'] || []
|
|
||||||
table = rows.map do |row|
|
|
||||||
cells = row['table_row']['cells']
|
|
||||||
cells.map { |cell| rich_text_to_md(cell) }
|
|
||||||
end
|
|
||||||
return '' if table.empty?
|
|
||||||
|
|
||||||
header = table.first
|
|
||||||
sep = header.map { '---' }
|
|
||||||
([header, sep] + table[1..]).map { |row| "| #{row.join(' | ')} |" }.join("\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -8,25 +8,17 @@ class Telegram::IncomingMessageService
|
|||||||
|
|
||||||
def perform
|
def perform
|
||||||
# chatwoot doesn't support group conversations at the moment
|
# chatwoot doesn't support group conversations at the moment
|
||||||
transform_business_message!
|
|
||||||
return unless private_message?
|
return unless private_message?
|
||||||
|
|
||||||
set_contact
|
set_contact
|
||||||
update_contact_avatar
|
update_contact_avatar
|
||||||
set_conversation
|
set_conversation
|
||||||
# TODO: Since the recent Telegram Business update, we need to explicitly mark messages as read using an additional request.
|
|
||||||
# Otherwise, the client will see their messages as unread.
|
|
||||||
# Chatwoot defines a 'read' status in its enum but does not currently update this status for Telegram conversations.
|
|
||||||
# We have two options:
|
|
||||||
# 1. Send the read request to Telegram here, immediately when the message is created.
|
|
||||||
# 2. Properly update the read status in the Chatwoot UI and trigger the Telegram request when the agent actually reads the message.
|
|
||||||
# See: https://core.telegram.org/bots/api#readbusinessmessage
|
|
||||||
@message = @conversation.messages.build(
|
@message = @conversation.messages.build(
|
||||||
content: telegram_params_message_content,
|
content: telegram_params_message_content,
|
||||||
account_id: @inbox.account_id,
|
account_id: @inbox.account_id,
|
||||||
inbox_id: @inbox.id,
|
inbox_id: @inbox.id,
|
||||||
message_type: message_type,
|
message_type: :incoming,
|
||||||
sender: message_sender,
|
sender: @contact,
|
||||||
content_attributes: telegram_params_content_attributes,
|
content_attributes: telegram_params_content_attributes,
|
||||||
source_id: telegram_params_message_id.to_s
|
source_id: telegram_params_message_id.to_s
|
||||||
)
|
)
|
||||||
@@ -44,11 +36,6 @@ class Telegram::IncomingMessageService
|
|||||||
contact_attributes: contact_attributes
|
contact_attributes: contact_attributes
|
||||||
).perform
|
).perform
|
||||||
|
|
||||||
# TODO: Should we update contact_attributes when the user changes their first or last name?
|
|
||||||
# In business chats, when our Telegram bot initiates the conversation,
|
|
||||||
# the message does not include a language code.
|
|
||||||
# This is critical for AI assistants and translation plugins.
|
|
||||||
|
|
||||||
@contact_inbox = contact_inbox
|
@contact_inbox = contact_inbox
|
||||||
@contact = contact_inbox.contact
|
@contact = contact_inbox.contact
|
||||||
end
|
end
|
||||||
@@ -102,19 +89,10 @@ class Telegram::IncomingMessageService
|
|||||||
|
|
||||||
def conversation_additional_attributes
|
def conversation_additional_attributes
|
||||||
{
|
{
|
||||||
chat_id: telegram_params_chat_id,
|
chat_id: telegram_params_chat_id
|
||||||
business_connection_id: telegram_params_business_connection_id
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def message_type
|
|
||||||
business_message_outgoing? ? :outgoing : :incoming
|
|
||||||
end
|
|
||||||
|
|
||||||
def message_sender
|
|
||||||
business_message_outgoing? ? nil : @contact
|
|
||||||
end
|
|
||||||
|
|
||||||
def file_content_type
|
def file_content_type
|
||||||
return :image if image_message?
|
return :image if image_message?
|
||||||
return :audio if audio_message?
|
return :audio if audio_message?
|
||||||
@@ -213,8 +191,4 @@ class Telegram::IncomingMessageService
|
|||||||
params[:message][:video].presence ||
|
params[:message][:video].presence ||
|
||||||
params[:message][:video_note].presence
|
params[:message][:video_note].presence
|
||||||
end
|
end
|
||||||
|
|
||||||
def transform_business_message!
|
|
||||||
params[:message] = params[:business_message] if params[:business_message] && !params[:message]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -13,17 +13,6 @@ module Telegram::ParamHelpers
|
|||||||
{}
|
{}
|
||||||
end
|
end
|
||||||
|
|
||||||
def business_message?
|
|
||||||
telegram_params_business_connection_id.present?
|
|
||||||
end
|
|
||||||
|
|
||||||
# In business bot mode we will receive messages from our telegram.
|
|
||||||
# This is our messages posted via telegram client.
|
|
||||||
# Such messages should be outgoing (from us to client)
|
|
||||||
def business_message_outgoing?
|
|
||||||
business_message? && telegram_params_base_object[:chat][:id] != telegram_params_base_object[:from][:id]
|
|
||||||
end
|
|
||||||
|
|
||||||
def message_params?
|
def message_params?
|
||||||
params[:message].present?
|
params[:message].present?
|
||||||
end
|
end
|
||||||
@@ -40,34 +29,24 @@ module Telegram::ParamHelpers
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def contact_params
|
|
||||||
if business_message_outgoing?
|
|
||||||
telegram_params_base_object[:chat]
|
|
||||||
else
|
|
||||||
telegram_params_base_object[:from]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def telegram_params_from_id
|
def telegram_params_from_id
|
||||||
return telegram_params_base_object[:chat][:id] if business_message?
|
|
||||||
|
|
||||||
telegram_params_base_object[:from][:id]
|
telegram_params_base_object[:from][:id]
|
||||||
end
|
end
|
||||||
|
|
||||||
def telegram_params_first_name
|
def telegram_params_first_name
|
||||||
contact_params[:first_name]
|
telegram_params_base_object[:from][:first_name]
|
||||||
end
|
end
|
||||||
|
|
||||||
def telegram_params_last_name
|
def telegram_params_last_name
|
||||||
contact_params[:last_name]
|
telegram_params_base_object[:from][:last_name]
|
||||||
end
|
end
|
||||||
|
|
||||||
def telegram_params_username
|
def telegram_params_username
|
||||||
contact_params[:username]
|
telegram_params_base_object[:from][:username]
|
||||||
end
|
end
|
||||||
|
|
||||||
def telegram_params_language_code
|
def telegram_params_language_code
|
||||||
contact_params[:language_code]
|
telegram_params_base_object[:from][:language_code]
|
||||||
end
|
end
|
||||||
|
|
||||||
def telegram_params_chat_id
|
def telegram_params_chat_id
|
||||||
@@ -78,14 +57,6 @@ module Telegram::ParamHelpers
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def telegram_params_business_connection_id
|
|
||||||
if callback_query_params?
|
|
||||||
params[:callback_query][:message][:business_connection_id]
|
|
||||||
else
|
|
||||||
telegram_params_base_object[:business_connection_id]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def telegram_params_message_content
|
def telegram_params_message_content
|
||||||
if callback_query_params?
|
if callback_query_params?
|
||||||
params[:callback_query][:data]
|
params[:callback_query][:data]
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ class Telegram::SendAttachmentsService
|
|||||||
HTTParty.post("#{channel.telegram_api_url}/sendMediaGroup",
|
HTTParty.post("#{channel.telegram_api_url}/sendMediaGroup",
|
||||||
body: {
|
body: {
|
||||||
chat_id: chat_id,
|
chat_id: chat_id,
|
||||||
**business_connection_body,
|
|
||||||
media: attachments.map { |hash| hash.except(:attachment) }.to_json,
|
media: attachments.map { |hash| hash.except(:attachment) }.to_json,
|
||||||
reply_to_message_id: reply_to_message_id
|
reply_to_message_id: reply_to_message_id
|
||||||
})
|
})
|
||||||
@@ -109,7 +108,6 @@ class Telegram::SendAttachmentsService
|
|||||||
HTTParty.post("#{channel.telegram_api_url}/sendDocument",
|
HTTParty.post("#{channel.telegram_api_url}/sendDocument",
|
||||||
body: {
|
body: {
|
||||||
chat_id: chat_id,
|
chat_id: chat_id,
|
||||||
**business_connection_body,
|
|
||||||
document: file,
|
document: file,
|
||||||
reply_to_message_id: reply_to_message_id
|
reply_to_message_id: reply_to_message_id
|
||||||
},
|
},
|
||||||
@@ -137,14 +135,4 @@ class Telegram::SendAttachmentsService
|
|||||||
def channel
|
def channel
|
||||||
@channel ||= message.inbox.channel
|
@channel ||= message.inbox.channel
|
||||||
end
|
end
|
||||||
|
|
||||||
def business_connection_id
|
|
||||||
@business_connection_id ||= channel.business_connection_id(message)
|
|
||||||
end
|
|
||||||
|
|
||||||
def business_connection_body
|
|
||||||
body = {}
|
|
||||||
body[:business_connection_id] = business_connection_id if business_connection_id
|
|
||||||
body
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ class Telegram::UpdateMessageService
|
|||||||
pattr_initialize [:inbox!, :params!]
|
pattr_initialize [:inbox!, :params!]
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
transform_business_message!
|
|
||||||
find_contact_inbox
|
find_contact_inbox
|
||||||
find_conversation
|
find_conversation
|
||||||
find_message
|
find_message
|
||||||
@@ -37,8 +36,4 @@ class Telegram::UpdateMessageService
|
|||||||
@message.update!(content: edited_message[:caption])
|
@message.update!(content: edited_message[:caption])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def transform_business_message!
|
|
||||||
params[:edited_message] = params[:edited_business_message] if params[:edited_business_message].present?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,9 +4,7 @@
|
|||||||
I18n.t('reports.label_csv.label_title'),
|
I18n.t('reports.label_csv.label_title'),
|
||||||
I18n.t('reports.label_csv.conversations_count'),
|
I18n.t('reports.label_csv.conversations_count'),
|
||||||
I18n.t('reports.label_csv.avg_first_response_time'),
|
I18n.t('reports.label_csv.avg_first_response_time'),
|
||||||
I18n.t('reports.label_csv.avg_resolution_time'),
|
I18n.t('reports.label_csv.avg_resolution_time')
|
||||||
I18n.t('reports.label_csv.avg_reply_time'),
|
|
||||||
I18n.t('reports.label_csv.resolution_count'),
|
|
||||||
]
|
]
|
||||||
%>
|
%>
|
||||||
<%= CSVSafe.generate_line headers -%>
|
<%= CSVSafe.generate_line headers -%>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
%>
|
%>
|
||||||
<%= javascript_include_tag "secretField" %>
|
<%= javascript_include_tag "secretField" %>
|
||||||
<div data-secret-text="<%= field.data %>" class="cell-data__secret-field">
|
<div data-secret-text="<%= field.data %>" class="cell-data__secret-field">
|
||||||
<span data-secret-masked="true"></span>
|
<span data-secret-masked="true">••••••••••</span>
|
||||||
<button onclick="toggleSecretField(event)" data-secret-toggler>
|
<button onclick="toggleSecretField(event)" data-secret-toggler>
|
||||||
<svg width="20" height="20">
|
<svg width="20" height="20">
|
||||||
<use xlink:href="#eye-show" />
|
<use xlink:href="#eye-show" />
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<%= javascript_include_tag "secretField" %>
|
<%= javascript_include_tag "secretField" %>
|
||||||
|
|
||||||
<div data-secret-text="<%= field.data %>" class="cell-data__secret-field">
|
<div data-secret-text="<%= field.data %>" class="cell-data__secret-field">
|
||||||
<span data-secret-masked="true"></span>
|
<span data-secret-masked="true">••••••••••</span>
|
||||||
<button onclick="toggleSecretField(event)" data-secret-toggler>
|
<button onclick="toggleSecretField(event)" data-secret-toggler>
|
||||||
<svg width="20" height="20">
|
<svg width="20" height="20">
|
||||||
<use xlink:href="#eye-show" />
|
<use xlink:href="#eye-show" />
|
||||||
|
|||||||
+1
-1
@@ -6,8 +6,8 @@
|
|||||||
<strong>Chatwoot Installation:</strong> {{ meta.instance_url }}<br>
|
<strong>Chatwoot Installation:</strong> {{ meta.instance_url }}<br>
|
||||||
<strong>Account ID:</strong> {{ meta.account_id }}<br>
|
<strong>Account ID:</strong> {{ meta.account_id }}<br>
|
||||||
<strong>Account Name:</strong> {{ meta.account_name }}<br>
|
<strong>Account Name:</strong> {{ meta.account_name }}<br>
|
||||||
<strong>Deletion due at:</strong> {{ meta.marked_for_deletion_at }}<br>
|
|
||||||
<strong>Deleted At:</strong> {{ meta.deleted_at }}<br>
|
<strong>Deleted At:</strong> {{ meta.deleted_at }}<br>
|
||||||
|
<strong>Marked for Deletion at:</strong> {{ meta.marked_for_deletion_at }}<br>
|
||||||
<strong>Deletion Reason:</strong> {{ meta.deletion_reason }}
|
<strong>Deletion Reason:</strong> {{ meta.deletion_reason }}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
<header class="sticky top-0 z-50 w-full bg-white shadow-sm dark:bg-slate-900">
|
<header class="sticky top-0 z-50 w-full bg-white shadow-sm dark:bg-slate-900">
|
||||||
<nav class="hidden sm:flex max-w-5xl px-4 mx-auto md:px-8" aria-label="Top">
|
<nav class="hidden sm:flex max-w-5xl px-4 mx-auto md:px-8" aria-label="Top">
|
||||||
<div class="flex items-center w-full py-5 overflow-hidden">
|
<div class="flex items-center w-full py-5 overflow-hidden">
|
||||||
<a href="<%= generate_home_link(@portal.slug, @portal.config['default_locale'] || params[:locale], @theme_from_params, @is_plain_layout_enabled) %>" class="flex items-center min-w-0 h-10">
|
<a href="<%= generate_home_link(@portal.slug, @portal.config['default_locale'] || params[:locale], @theme_from_params, @is_plain_layout_enabled) %>" class="flex items-center h-10">
|
||||||
<% if @portal.logo.present? %>
|
<% if @portal.logo.present? %>
|
||||||
<img src="<%= url_for(@portal.logo) %>" class="w-auto h-10 ltr:mr-2 rtl:ml-2" draggable="false" />
|
<img src="<%= url_for(@portal.logo) %>" class="w-auto h-10 ltr:mr-2 rtl:ml-2" />
|
||||||
<% end %>
|
<% end %>
|
||||||
<span class="text-lg font-semibold text-slate-900 truncate dark:text-white <%= @portal.logo.present? ? 'hidden lg:block' : 'hidden sm:block' %>"><%= @portal.name %></span>
|
<span class="text-lg font-semibold text-slate-900 dark:text-white <%= @portal.logo.present? ? 'hidden' : 'hidden sm:block' %>"><%= @portal.name %></span>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%# Go to homepage link section %>
|
<%# Go to homepage link section %>
|
||||||
<div class="flex items-center justify-between gap-2 sm:gap-5">
|
<div class="flex items-center justify-between gap-2 sm:gap-5">
|
||||||
<% if @portal.homepage_link %>
|
<% if @portal.homepage_link %>
|
||||||
<div class="px-1 py-2 ltr:ml-8 rtl:mr-8 cursor-pointer block">
|
<div class="hidden px-1 py-2 ltr:ml-8 rtl:mr-8 cursor-pointer md:block">
|
||||||
<div class="flex-grow flex-shrink-0">
|
<div class="flex-grow flex-shrink-0">
|
||||||
<a id="header-action-button" target="_blank" rel="noopener noreferrer nofollow" href="<%= @portal.homepage_link %>" class="flex flex-row items-center gap-1 text-sm font-medium whitespace-nowrap text-slate-800 dark:text-slate-100 stroke-slate-700 dark:stroke-slate-200">
|
<a id="header-action-button" target="_blank" rel="noopener noreferrer nofollow" href="<%= @portal.homepage_link %>" class="flex flex-row items-center gap-1 text-sm font-medium whitespace-nowrap text-slate-800 dark:text-slate-100 stroke-slate-700 dark:stroke-slate-200">
|
||||||
<%= render partial: 'icons/redirect' %>
|
<%= render partial: 'icons/redirect' %>
|
||||||
@@ -99,11 +99,11 @@
|
|||||||
|
|
||||||
<nav class="flex sm:hidden max-w-5xl px-4 mx-auto" aria-label="Mobile Top">
|
<nav class="flex sm:hidden max-w-5xl px-4 mx-auto" aria-label="Mobile Top">
|
||||||
<div class="flex items-center justify-between w-full py-5">
|
<div class="flex items-center justify-between w-full py-5">
|
||||||
<a href="<%= generate_home_link(@portal.slug, @portal.config['default_locale'] || params[:locale], @theme_from_params, @is_plain_layout_enabled) %>" class="flex items-center min-w-0 h-10 text-lg font-semibold text-slate-900 dark:text-white">
|
<a href="<%= generate_home_link(@portal.slug, @portal.config['default_locale'] || params[:locale], @theme_from_params, @is_plain_layout_enabled) %>" class="flex items-center h-10 text-lg font-semibold text-slate-900 dark:text-white">
|
||||||
<% if @portal.logo.present? %>
|
<% if @portal.logo.present? %>
|
||||||
<img src="<%= url_for(@portal.logo) %>" class="w-auto h-10 ltr:mr-2 rtl:ml-2" draggable="false" />
|
<img src="<%= url_for(@portal.logo) %>" class="w-auto h-10 ltr:mr-2 rtl:ml-2" />
|
||||||
<% end %>
|
<% end %>
|
||||||
<span class="text-lg font-semibold text-slate-900 truncate dark:text-white <%= @portal.logo.present? ? 'hidden' : 'sm:hidden block' %>"><%= @portal.name %></span>
|
<span class="text-lg font-semibold text-slate-900 dark:text-white <%= @portal.logo.present? ? 'hidden' : 'sm:hidden block' %>"><%= @portal.name %></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Mobile Menu Component -->
|
<!-- Mobile Menu Component -->
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<section id="portal-bg" class="w-full bg-white dark:bg-slate-900 shadow-inner">
|
<section id="portal-bg" class="w-full bg-white dark:bg-slate-900 shadow-inner">
|
||||||
<div id="portal-bg-gradient" class="pt-8 pb-8 md:pt-14 md:pb-6 min-h-[240px] md:min-h-[260px]">
|
<div id="portal-bg-gradient" class="pt-8 pb-8 md:pt-14 md:pb-6 min-h-[240px] md:min-h-[260px]">
|
||||||
<div class="mx-auto max-w-5xl px-4 md:px-8 flex flex-col items-start">
|
<div class="mx-auto max-w-5xl px-4 md:px-8 flex flex-col items-start">
|
||||||
<span class="text-sm leading-[24px] font-semibold text-slate-600 dark:text-slate-300 mb-1 <%= @portal.logo.present? ? 'block lg:hidden' : 'hidden' %>"><%= @portal.name %></span>
|
<span class="text-sm leading-[24px] font-semibold text-slate-600 dark:text-slate-300 mb-1 <%= @portal.logo.present? ? 'block' : 'hidden' %>"><%= @portal.name %></span>
|
||||||
<h1 class="text-2xl md:text-4xl text-slate-900 dark:text-white font-semibold leading-normal">
|
<h1 class="text-2xl md:text-4xl text-slate-900 dark:text-white font-semibold leading-normal">
|
||||||
<%= portal.header_text %>
|
<%= portal.header_text %>
|
||||||
</h1>
|
</h1>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
<% has_multiple_locales = @portal.config["allowed_locales"].length > 1 %>
|
|
||||||
|
|
||||||
<input type="checkbox" id="mobile-menu-toggle" class="peer/menu hidden" />
|
<input type="checkbox" id="mobile-menu-toggle" class="peer/menu hidden" />
|
||||||
|
|
||||||
@@ -47,12 +46,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% if has_multiple_locales %>
|
<span class="h-px bg-slate-100/70 dark:bg-slate-800/70 w-full"></span>
|
||||||
<span class="h-px bg-slate-100/70 dark:bg-slate-800/70 w-full"></span>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<!-- Locale Switcher -->
|
<!-- Locale Switcher -->
|
||||||
<% if has_multiple_locales %>
|
<% if @portal.config["allowed_locales"].length > 1 %>
|
||||||
<div id="header-action-button" class="flex flex-col gap-2">
|
<div id="header-action-button" class="flex flex-col gap-2">
|
||||||
<h3 class="text-base font-medium text-slate-700 dark:text-slate-300 my-2">
|
<h3 class="text-base font-medium text-slate-700 dark:text-slate-300 my-2">
|
||||||
<%= I18n.t('public_portal.header.language', default: 'Language') %>
|
<%= I18n.t('public_portal.header.language', default: 'Language') %>
|
||||||
|
|||||||
@@ -156,14 +156,12 @@
|
|||||||
<path d="M 8 3 C 5.243 3 3 5.243 3 8 L 3 16 C 3 18.757 5.243 21 8 21 L 16 21 C 18.757 21 21 18.757 21 16 L 21 8 C 21 5.243 18.757 3 16 3 L 8 3 z M 8 5 L 16 5 C 17.654 5 19 6.346 19 8 L 19 16 C 19 17.654 17.654 19 16 19 L 8 19 C 6.346 19 5 17.654 5 16 L 5 8 C 5 6.346 6.346 5 8 5 z M 17 6 A 1 1 0 0 0 16 7 A 1 1 0 0 0 17 8 A 1 1 0 0 0 18 7 A 1 1 0 0 0 17 6 z M 12 7 C 9.243 7 7 9.243 7 12 C 7 14.757 9.243 17 12 17 C 14.757 17 17 14.757 17 12 C 17 9.243 14.757 7 12 7 z M 12 9 C 13.654 9 15 10.346 15 12 C 15 13.654 13.654 15 12 15 C 10.346 15 9 13.654 9 12 C 9 10.346 10.346 9 12 9 z"/>
|
<path d="M 8 3 C 5.243 3 3 5.243 3 8 L 3 16 C 3 18.757 5.243 21 8 21 L 16 21 C 18.757 21 21 18.757 21 16 L 21 8 C 21 5.243 18.757 3 16 3 L 8 3 z M 8 5 L 16 5 C 17.654 5 19 6.346 19 8 L 19 16 C 19 17.654 17.654 19 16 19 L 8 19 C 6.346 19 5 17.654 5 16 L 5 8 C 5 6.346 6.346 5 8 5 z M 17 6 A 1 1 0 0 0 16 7 A 1 1 0 0 0 17 8 A 1 1 0 0 0 18 7 A 1 1 0 0 0 17 6 z M 12 7 C 9.243 7 7 9.243 7 12 C 7 14.757 9.243 17 12 17 C 14.757 17 17 14.757 17 12 C 17 9.243 14.757 7 12 7 z M 12 9 C 13.654 9 15 10.346 15 12 C 15 13.654 13.654 15 12 15 C 10.346 15 9 13.654 9 12 C 9 10.346 10.346 9 12 9 z"/>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
|
||||||
<symbol id="icon-notion" viewBox="0 0 24 24">
|
|
||||||
<path fill="currentColor" d="M6.104 5.91c.584.474.802.438 1.898.365l10.332-.62c.22 0 .037-.22-.036-.256l-1.716-1.24c-.329-.255-.767-.548-1.606-.475l-10.005.73c-.364.036-.437.219-.292.365zm.62 2.408v10.87c0 .585.292.803.95.767l11.354-.657c.657-.036.73-.438.73-.913V7.588c0-.474-.182-.73-.584-.693l-11.866.693c-.438.036-.584.255-.584.73m11.21.583c.072.328 0 .657-.33.694l-.547.109v8.025c-.475.256-.913.401-1.278.401c-.584 0-.73-.182-1.168-.729l-3.579-5.618v5.436l1.133.255s0 .656-.914.656l-2.519.146c-.073-.146 0-.51.256-.583l.657-.182v-7.187l-.913-.073c-.073-.329.11-.803.621-.84l2.702-.182l3.724 5.692V9.886l-.95-.109c-.072-.402.22-.693.585-.73zM4.131 3.429l10.406-.766c1.277-.11 1.606-.036 2.41.547l3.321 2.335c.548.401.731.51.731.948v12.805c0 .803-.292 1.277-1.314 1.35l-12.085.73c-.767.036-1.132-.073-1.534-.584L3.62 17.62c-.438-.584-.62-1.021-.62-1.533V4.705c0-.656.292-1.203 1.132-1.276"/>
|
|
||||||
</symbol>
|
|
||||||
|
|
||||||
<symbol id="icon-shopify" viewBox="0 0 32 32">
|
<symbol id="icon-shopify" viewBox="0 0 32 32">
|
||||||
<path fill="currentColor" d="m20.448 31.974l9.625-2.083s-3.474-23.484-3.5-23.641s-.156-.255-.281-.255c-.13 0-2.573-.182-2.573-.182s-1.703-1.698-1.922-1.88a.4.4 0 0 0-.161-.099l-1.219 28.141zm-4.833-16.901s-1.083-.563-2.365-.563c-1.932 0-2.005 1.203-2.005 1.521c0 1.641 4.318 2.286 4.318 6.172c0 3.057-1.922 5.01-4.542 5.01c-3.141 0-4.719-1.953-4.719-1.953l.859-2.781s1.661 1.422 3.042 1.422c.901 0 1.302-.724 1.302-1.245c0-2.156-3.542-2.255-3.542-5.807c-.047-2.984 2.094-5.891 6.438-5.891c1.677 0 2.5.479 2.5.479l-1.26 3.625zm-.719-13.969c.177 0 .359.052.536.182c-1.313.62-2.75 2.188-3.344 5.323a76 76 0 0 1-2.516.771c.688-2.38 2.359-6.26 5.323-6.26zm1.646 3.932v.182c-1.005.307-2.115.646-3.193.979c.62-2.37 1.776-3.526 2.781-3.958c.255.667.411 1.568.411 2.797zm.718-2.973c.922.094 1.521 1.151 1.901 2.339c-.464.151-.979.307-1.542.484v-.333c0-1.005-.13-1.828-.359-2.495zm3.99 1.718c-.031 0-.083.026-.104.026c-.026 0-.385.099-.953.281C19.63 2.442 18.625.927 16.849.927h-.156C16.183.281 15.558 0 15.021 0c-4.141 0-6.12 5.172-6.74 7.797c-1.594.484-2.75.844-2.88.896c-.901.286-.927.313-1.031 1.161c-.099.615-2.438 18.75-2.438 18.75L20.01 32z"/>
|
<path fill="currentColor" d="m20.448 31.974l9.625-2.083s-3.474-23.484-3.5-23.641s-.156-.255-.281-.255c-.13 0-2.573-.182-2.573-.182s-1.703-1.698-1.922-1.88a.4.4 0 0 0-.161-.099l-1.219 28.141zm-4.833-16.901s-1.083-.563-2.365-.563c-1.932 0-2.005 1.203-2.005 1.521c0 1.641 4.318 2.286 4.318 6.172c0 3.057-1.922 5.01-4.542 5.01c-3.141 0-4.719-1.953-4.719-1.953l.859-2.781s1.661 1.422 3.042 1.422c.901 0 1.302-.724 1.302-1.245c0-2.156-3.542-2.255-3.542-5.807c-.047-2.984 2.094-5.891 6.438-5.891c1.677 0 2.5.479 2.5.479l-1.26 3.625zm-.719-13.969c.177 0 .359.052.536.182c-1.313.62-2.75 2.188-3.344 5.323a76 76 0 0 1-2.516.771c.688-2.38 2.359-6.26 5.323-6.26zm1.646 3.932v.182c-1.005.307-2.115.646-3.193.979c.62-2.37 1.776-3.526 2.781-3.958c.255.667.411 1.568.411 2.797zm.718-2.973c.922.094 1.521 1.151 1.901 2.339c-.464.151-.979.307-1.542.484v-.333c0-1.005-.13-1.828-.359-2.495zm3.99 1.718c-.031 0-.083.026-.104.026c-.026 0-.385.099-.953.281C19.63 2.442 18.625.927 16.849.927h-.156C16.183.281 15.558 0 15.021 0c-4.141 0-6.12 5.172-6.74 7.797c-1.594.484-2.75.844-2.88.896c-.901.286-.927.313-1.031 1.161c-.099.615-2.438 18.75-2.438 18.75L20.01 32z"/>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
<symbol id="icon-github" viewBox="0 0 24 24">
|
||||||
|
<path fill="currentColor" d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||||||
|
</symbol>
|
||||||
<symbol id="icon-slack" viewBox="0 0 24 24">
|
<symbol id="icon-slack" viewBox="0 0 24 24">
|
||||||
<path fill="currentColor" d="M6.527 14.514A1.973 1.973 0 0 1 4.56 16.48a1.973 1.973 0 0 1-1.968-1.967c0-1.083.885-1.968 1.968-1.968h1.967zm.992 0c0-1.083.885-1.968 1.968-1.968s1.967.885 1.967 1.968v4.927a1.973 1.973 0 0 1-1.967 1.968a1.973 1.973 0 0 1-1.968-1.968zm1.968-7.987A1.973 1.973 0 0 1 7.519 4.56c0-1.083.885-1.967 1.968-1.967s1.967.884 1.967 1.967v1.968zm0 .992c1.083 0 1.967.884 1.967 1.967a1.973 1.973 0 0 1-1.967 1.968H4.56a1.973 1.973 0 0 1-1.968-1.968c0-1.083.885-1.967 1.968-1.967zm7.986 1.967c0-1.083.885-1.967 1.968-1.967s1.968.884 1.968 1.967a1.973 1.973 0 0 1-1.968 1.968h-1.968zm-.991 0a1.973 1.973 0 0 1-1.968 1.968a1.973 1.973 0 0 1-1.968-1.968V4.56c0-1.083.885-1.967 1.968-1.967s1.968.884 1.968 1.967zm-1.968 7.987c1.083 0 1.968.885 1.968 1.968a1.973 1.973 0 0 1-1.968 1.968a1.973 1.973 0 0 1-1.968-1.968v-1.968zm0-.992a1.973 1.973 0 0 1-1.968-1.967c0-1.083.885-1.968 1.968-1.968h4.927c1.083 0 1.968.885 1.968 1.968a1.973 1.973 0 0 1-1.968 1.967z"/>
|
<path fill="currentColor" d="M6.527 14.514A1.973 1.973 0 0 1 4.56 16.48a1.973 1.973 0 0 1-1.968-1.967c0-1.083.885-1.968 1.968-1.968h1.967zm.992 0c0-1.083.885-1.968 1.968-1.968s1.967.885 1.967 1.968v4.927a1.973 1.973 0 0 1-1.967 1.968a1.973 1.973 0 0 1-1.968-1.968zm1.968-7.987A1.973 1.973 0 0 1 7.519 4.56c0-1.083.885-1.967 1.968-1.967s1.967.884 1.967 1.967v1.968zm0 .992c1.083 0 1.967.884 1.967 1.967a1.973 1.973 0 0 1-1.967 1.968H4.56a1.973 1.973 0 0 1-1.968-1.968c0-1.083.885-1.967 1.968-1.967zm7.986 1.967c0-1.083.885-1.967 1.968-1.967s1.968.884 1.968 1.967a1.973 1.973 0 0 1-1.968 1.968h-1.968zm-.991 0a1.973 1.973 0 0 1-1.968 1.968a1.973 1.973 0 0 1-1.968-1.968V4.56c0-1.083.885-1.967 1.968-1.967s1.968.884 1.968 1.967zm-1.968 7.987c1.083 0 1.968.885 1.968 1.968a1.973 1.973 0 0 1-1.968 1.968a1.973 1.973 0 0 1-1.968-1.968v-1.968zm0-.992a1.973 1.973 0 0 1-1.968-1.967c0-1.083.885-1.968 1.968-1.968h4.927c1.083 0 1.968.885 1.968 1.968a1.973 1.973 0 0 1-1.968 1.967z"/>
|
||||||
</symbol>
|
</symbol>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
@@ -22,36 +22,27 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<div class="bg-white py-2 px-4 xl:px-0">
|
<div class="bg-white py-2 px-4 xl:px-0">
|
||||||
<%= javascript_include_tag "secretField" %>
|
<div class="mb-4">
|
||||||
<div class="flex items-center mb-6">
|
<div class="flex items-center gap-2">
|
||||||
<h4 class="text-sm font-medium leading-5 h-5 text-n-slate-12 mr-4">Installation Identifier</h4>
|
<h2 class="h-5 leading-5 text-n-slate-12 font-medium">Current plan</h2>
|
||||||
<div data-secret-text="<%= ChatwootHub.installation_identifier %>" class="cell-data__secret-field text-sm leading-5 h-5 text-n-slate-11">
|
<a href="<%= refresh_super_admin_settings_url %>" class="inline-flex gap-1 text-xs font-medium items-center text-woot-500 hover:text-woot-700">
|
||||||
<span data-secret-masked="true" class="select-none"></span>
|
<svg width="16" height="16"><use xlink:href="#icon-refresh-line" /></svg>
|
||||||
<button type="button" onclick="toggleSecretField(event)" data-secret-toggler class="inline-flex items-center justify-center h-5 w-5 p-0 rounded text-n-slate-11 hover:text-n-slate-12 transition-colors focus:outline-none">
|
<span>Refresh</span>
|
||||||
<svg width="20" height="20" class="w-5 h-5 fill-current">
|
</a>
|
||||||
<use xlink:href="#eye-show" />
|
</div>
|
||||||
</svg>
|
<p class="text-n-slate-11 mt-1"><%= SuperAdmin::FeaturesHelper.plan_details.html_safe %></p>
|
||||||
</button>
|
<div class="flex items-center mt-6">
|
||||||
<button type="button" onclick="copySecretField(event)" data-secret-copier class="inline-flex items-center justify-center h-5 w-5 p-0 rounded text-n-slate-11 hover:text-n-slate-12 transition-colors focus:outline-none">
|
<h4 class="text-sm font-medium leading-5 h-5 text-n-slate-12 mr-4">Installation Identifier</h4>
|
||||||
<svg width="20" height="20" class="w-5 h-5 fill-current">
|
<span class="text-sm leading-5 h-5 text-n-slate-11"><%= ChatwootHub.installation_identifier %></span>
|
||||||
<use xlink:href="#icon-copy" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex p-4 outline outline-1 outline-n-container rounded-lg items-start md:items-center shadow-sm flex-col md:flex-row">
|
<div class="flex p-4 outline outline-1 outline-n-container rounded-lg mt-8 items-start md:items-center shadow-sm flex-col md:flex-row">
|
||||||
<div class="flex flex-col flex-grow gap-1">
|
<div class="flex flex-col flex-grow gap-1">
|
||||||
<div class="flex items-center gap-2">
|
<h2 class="h-5 leading-5 text-n-slate-12 text-sm font-medium">Current plan</h2>
|
||||||
<h2 class="h-5 leading-5 text-n-slate-12 text-sm font-medium">Current plan</h2>
|
|
||||||
<a href="<%= refresh_super_admin_settings_url %>" class="inline-flex gap-1 text-xs font-medium items-center text-woot-500 hover:text-woot-700">
|
|
||||||
<svg width="16" height="16"><use xlink:href="#icon-refresh-line" /></svg>
|
|
||||||
<span>Refresh</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<p class="text-n-slate-11 m-0 text-sm"><%= SuperAdmin::FeaturesHelper.plan_details.html_safe %></p>
|
<p class="text-n-slate-11 m-0 text-sm"><%= SuperAdmin::FeaturesHelper.plan_details.html_safe %></p>
|
||||||
</div>
|
</div>
|
||||||
<a href="<%= ChatwootHub.billing_url %>" target="_blank" rel="noopener noreferrer">
|
<a href="<%= ChatwootHub.billing_url %>" target="_blank" rel="noopener noreferrer">
|
||||||
<button class="mt-4 md:mt-0 flex gap-1 items-center bg-transparent shadow-sm h-9 hover:text-n-slate-12 hover:bg-slate-50 outline outline-1 outline-n-container rounded text-n-slate-11 font-medium p-2 focus:outline-none">
|
<button class="mt-4 md:mt-0 flex gap-1 items-center bg-transparent shadow-sm h-9 hover:text-n-slate-12 hover:bg-slate-50 outline outline-1 outline-n-container rounded text-n-slate-11 font-medium p-2">
|
||||||
<svg width="16" height="16"><use xlink:href="#icon-settings-2-line" /></svg>
|
<svg width="16" height="16"><use xlink:href="#icon-settings-2-line" /></svg>
|
||||||
<span class="px-1">Manage</span>
|
<span class="px-1">Manage</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -73,14 +64,14 @@
|
|||||||
<p class="text-n-slate-11 m-0 text-sm">Do you face any issues? We are here to help.</p>
|
<p class="text-n-slate-11 m-0 text-sm">Do you face any issues? We are here to help.</p>
|
||||||
</div>
|
</div>
|
||||||
<a href="https://discord.gg/cJXdrwS" target="_blank">
|
<a href="https://discord.gg/cJXdrwS" target="_blank">
|
||||||
<button class="flex mt-4 md:mt-0 gap-1 items-center bg-transparent shadow-sm h-9 bg-violet-500 hover:bg-violet-600 text-white border border-solid border-violet-600 rounded font-medium p-2 focus:outline-none">
|
<button class="flex mt-4 md:mt-0 gap-1 items-center bg-transparent shadow-sm h-9 bg-violet-500 hover:bg-violet-600 text-white border border-solid border-violet-600 rounded font-medium p-2">
|
||||||
<svg class="h-4 w-4" width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13.209 3.103c-.495-1.004-1.926-1.004-2.421 0L8.43 7.88l-5.273.766c-1.107.161-1.55 1.522-.748 2.303l3.815 3.72-.9 5.25c-.19 1.103.968 1.944 1.959 1.424l4.715-2.48 4.716 2.48c.99.52 2.148-.32 1.96-1.424l-.902-5.25 3.816-3.72c.8-.78.359-2.142-.748-2.303l-5.273-.766-2.358-4.777ZM9.74 8.615l2.258-4.576 2.259 4.576a1.35 1.35 0 0 0 1.016.738l5.05.734-3.654 3.562a1.35 1.35 0 0 0-.388 1.195l.862 5.03-4.516-2.375a1.35 1.35 0 0 0-1.257 0l-4.516 2.374.862-5.029a1.35 1.35 0 0 0-.388-1.195l-3.654-3.562 5.05-.734c.44-.063.82-.34 1.016-.738ZM1.164 3.782a.75.75 0 0 0 .118 1.054l2.5 2a.75.75 0 1 0 .937-1.172l-2.5-2a.75.75 0 0 0-1.055.118Z" fill="currentColor"/><path d="M22.836 18.218a.75.75 0 0 0-.117-1.054l-2.5-2a.75.75 0 0 0-.938 1.172l2.5 2a.75.75 0 0 0 1.055-.117ZM1.282 17.164a.75.75 0 1 0 .937 1.172l2.5-2a.75.75 0 0 0-.937-1.172l-2.5 2ZM22.836 3.782a.75.75 0 0 1-.117 1.054l-2.5 2a.75.75 0 0 1-.938-1.172l2.5-2a.75.75 0 0 1 1.055.118Z" fill="currentColor"/></svg>
|
<svg class="h-4 w-4" width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10a9.96 9.96 0 0 1-4.587-1.112l-3.826 1.067a1.25 1.25 0 0 1-1.54-1.54l1.068-3.823A9.96 9.96 0 0 1 2 12C2 6.477 6.477 2 12 2Zm0 1.5A8.5 8.5 0 0 0 3.5 12c0 1.47.373 2.883 1.073 4.137l.15.27-1.112 3.984 3.987-1.112.27.15A8.5 8.5 0 1 0 12 3.5ZM8.75 13h4.498a.75.75 0 0 1 .102 1.493l-.102.007H8.75a.75.75 0 0 1-.102-1.493L8.75 13h4.498H8.75Zm0-3.5h6.505a.75.75 0 0 1 .101 1.493l-.101.007H8.75a.75.75 0 0 1-.102-1.493L8.75 9.5h6.505H8.75Z" fill="currentColor"/></svg>
|
||||||
<span class="px-1">Community Support</span>
|
<span class="px-1">Community Support</span>
|
||||||
</button>
|
</button>
|
||||||
</a>
|
</a>
|
||||||
<% if ChatwootHub.pricing_plan !='community' %>
|
<% if ChatwootHub.pricing_plan !='community' %>
|
||||||
<button class="ml-4 flex gap-1 items-center bg-transparent h-9 hover:text-n-slate-12 hover:bg-slate-50 border border-solid border-slate-100 rounded text-n-slate-11 font-medium p-2 focus:outline-none" onclick="window.$chatwoot.toggle('open')">
|
<button class="ml-4 flex gap-1 items-center bg-transparent h-9 hover:text-n-slate-12 hover:bg-slate-50 border border-solid border-slate-100 rounded text-n-slate-11 font-medium p-2" onclick="window.$chatwoot.toggle('open')">
|
||||||
<svg class="h-4 w-4" width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13.209 3.103c-.495-1.004-1.926-1.004-2.421 0L8.43 7.88l-5.273.766c-1.107.161-1.55 1.522-.748 2.303l3.815 3.72-.9 5.25c-.19 1.103.968 1.944 1.959 1.424l4.715-2.48 4.716 2.48c.99.52 2.148-.32 1.96-1.424l-.902-5.25 3.816-3.72c.8-.78.359-2.142-.748-2.303l-5.273-.766-2.358-4.777ZM9.74 8.615l2.258-4.576 2.259 4.576a1.35 1.35 0 0 0 1.016.738l5.05.734-3.654 3.562a1.35 1.35 0 0 0-.388 1.195l.862 5.03-4.516-2.375a1.35 1.35 0 0 0-1.257 0l-4.516 2.374.862-5.029a1.35 1.35 0 0 0-.388-1.195l-3.654-3.562 5.05-.734c.44-.063.82-.34 1.016-.738ZM1.164 3.782a.75.75 0 0 0 .118 1.054l2.5 2a.75.75 0 1 0 .937-1.172l-2.5-2a.75.75 0 0 0-1.055.118Z" fill="currentColor"/><path d="M22.836 18.218a.75.75 0 0 0-.117-1.054l-2.5-2a.75.75 0 0 0-.938 1.172l2.5 2a.75.75 0 0 0 1.055-.117ZM1.282 17.164a.75.75 0 1 0 .937 1.172l2.5-2a.75.75 0 0 0-.937-1.172l-2.5 2ZM22.836 3.782a.75.75 0 0 1-.117 1.054l-2.5 2a.75.75 0 0 1-.938-1.172l2.5-2a.75.75 0 0 1 1.055.118Z" fill="currentColor"/></svg>
|
<svg class="h-4 w-4" width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10a9.96 9.96 0 0 1-4.587-1.112l-3.826 1.067a1.25 1.25 0 0 1-1.54-1.54l1.068-3.823A9.96 9.96 0 0 1 2 12C2 6.477 6.477 2 12 2Zm0 1.5A8.5 8.5 0 0 0 3.5 12c0 1.47.373 2.883 1.073 4.137l.15.27-1.112 3.984 3.987-1.112.27.15A8.5 8.5 0 1 0 12 3.5ZM8.75 13h4.498a.75.75 0 0 1 .102 1.493l-.102.007H8.75a.75.75 0 0 1-.102-1.493L8.75 13h4.498H8.75Zm0-3.5h6.505a.75.75 0 0 1 .101 1.493l-.101.007H8.75a.75.75 0 0 1-.102-1.493L8.75 9.5h6.505H8.75Z" fill="currentColor"/></svg>
|
||||||
<span class="px-1">Chat Support</span>
|
<span class="px-1">Chat Support</span>
|
||||||
</button>
|
</button>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -99,7 +90,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<% if !attrs[:enabled] %>
|
<% if !attrs[:enabled] %>
|
||||||
<div class="flex h-9 absolute top-5 items-center invisible group-hover:visible">
|
<div class="flex h-9 absolute top-5 items-center invisible group-hover:visible">
|
||||||
<a href="<%= ChatwootHub.billing_url %>" target="_blank" rel="noopener noreferrer" class="flex gap-1 items-center bg-slate-100 h-9 hover:bg-slate-300 hover:text-n-slate-12 border border-solid border-slate-100 rounded text-n-slate-11 font-medium p-2 focus:outline-none">
|
<a href="<%= ChatwootHub.billing_url %>" target="_blank" rel="noopener noreferrer" class="flex gap-1 items-center bg-slate-100 h-9 hover:bg-slate-300 hover:text-n-slate-12 border border-solid border-slate-100 rounded text-n-slate-11 font-medium p-2">
|
||||||
<svg class="h-4 w-4" width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13.209 3.103c-.495-1.004-1.926-1.004-2.421 0L8.43 7.88l-5.273.766c-1.107.161-1.55 1.522-.748 2.303l3.815 3.72-.9 5.25c-.19 1.103.968 1.944 1.959 1.424l4.715-2.48 4.716 2.48c.99.52 2.148-.32 1.96-1.424l-.902-5.25 3.816-3.72c.8-.78.359-2.142-.748-2.303l-5.273-.766-2.358-4.777ZM9.74 8.615l2.258-4.576 2.259 4.576a1.35 1.35 0 0 0 1.016.738l5.05.734-3.654 3.562a1.35 1.35 0 0 0-.388 1.195l.862 5.03-4.516-2.375a1.35 1.35 0 0 0-1.257 0l-4.516 2.374.862-5.029a1.35 1.35 0 0 0-.388-1.195l-3.654-3.562 5.05-.734c.44-.063.82-.34 1.016-.738ZM1.164 3.782a.75.75 0 0 0 .118 1.054l2.5 2a.75.75 0 1 0 .937-1.172l-2.5-2a.75.75 0 0 0-1.055.118Z" fill="currentColor"/><path d="M22.836 18.218a.75.75 0 0 0-.117-1.054l-2.5-2a.75.75 0 0 0-.938 1.172l2.5 2a.75.75 0 0 0 1.055-.117ZM1.282 17.164a.75.75 0 1 0 .937 1.172l2.5-2a.75.75 0 0 0-.937-1.172l-2.5 2ZM22.836 3.782a.75.75 0 0 1-.117 1.054l-2.5 2a.75.75 0 0 1-.938-1.172l2.5-2a.75.75 0 0 1 1.055.118Z" fill="currentColor"/></svg>
|
<svg class="h-4 w-4" width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M13.209 3.103c-.495-1.004-1.926-1.004-2.421 0L8.43 7.88l-5.273.766c-1.107.161-1.55 1.522-.748 2.303l3.815 3.72-.9 5.25c-.19 1.103.968 1.944 1.959 1.424l4.715-2.48 4.716 2.48c.99.52 2.148-.32 1.96-1.424l-.902-5.25 3.816-3.72c.8-.78.359-2.142-.748-2.303l-5.273-.766-2.358-4.777ZM9.74 8.615l2.258-4.576 2.259 4.576a1.35 1.35 0 0 0 1.016.738l5.05.734-3.654 3.562a1.35 1.35 0 0 0-.388 1.195l.862 5.03-4.516-2.375a1.35 1.35 0 0 0-1.257 0l-4.516 2.374.862-5.029a1.35 1.35 0 0 0-.388-1.195l-3.654-3.562 5.05-.734c.44-.063.82-.34 1.016-.738ZM1.164 3.782a.75.75 0 0 0 .118 1.054l2.5 2a.75.75 0 1 0 .937-1.172l-2.5-2a.75.75 0 0 0-1.055.118Z" fill="currentColor"/><path d="M22.836 18.218a.75.75 0 0 0-.117-1.054l-2.5-2a.75.75 0 0 0-.938 1.172l2.5 2a.75.75 0 0 0 1.055-.117ZM1.282 17.164a.75.75 0 1 0 .937 1.172l2.5-2a.75.75 0 0 0-.937-1.172l-2.5 2ZM22.836 3.782a.75.75 0 0 1-.117 1.054l-2.5 2a.75.75 0 0 1-.938-1.172l2.5-2a.75.75 0 0 1 1.055.118Z" fill="currentColor"/></svg>
|
||||||
<span class="px-1">Upgrade now</span>
|
<span class="px-1">Upgrade now</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
shared: &shared
|
shared: &shared
|
||||||
version: '4.3.0'
|
version: '4.2.0'
|
||||||
|
|
||||||
development:
|
development:
|
||||||
<<: *shared
|
<<: *shared
|
||||||
|
|||||||
+3
-3
@@ -169,6 +169,6 @@
|
|||||||
- name: crm_integration
|
- name: crm_integration
|
||||||
display_name: CRM Integration
|
display_name: CRM Integration
|
||||||
enabled: false
|
enabled: false
|
||||||
- name: notion_integration
|
- name: github_integration
|
||||||
display_name: Notion Integration
|
display_name: Github Integration
|
||||||
enabled: false
|
enabled: false
|
||||||
@@ -288,25 +288,6 @@
|
|||||||
type: secret
|
type: secret
|
||||||
## ------ End of Configs added for Linear ------ ##
|
## ------ End of Configs added for Linear ------ ##
|
||||||
|
|
||||||
## ------ Configs added for Notion ------ ##
|
|
||||||
- name: NOTION_CLIENT_ID
|
|
||||||
display_title: 'Notion Client ID'
|
|
||||||
value:
|
|
||||||
locked: false
|
|
||||||
description: 'Notion client ID'
|
|
||||||
- name: NOTION_CLIENT_SECRET
|
|
||||||
display_title: 'Notion Client Secret'
|
|
||||||
value:
|
|
||||||
locked: false
|
|
||||||
description: 'Notion client secret'
|
|
||||||
type: secret
|
|
||||||
- name: NOTION_VERSION
|
|
||||||
display_title: 'Notion Version'
|
|
||||||
value: '2022-06-28'
|
|
||||||
locked: false
|
|
||||||
description: 'Notion version'
|
|
||||||
## ------ End of Configs added for Notion ------ ##
|
|
||||||
|
|
||||||
## ------ Configs added for Slack ------ ##
|
## ------ Configs added for Slack ------ ##
|
||||||
- name: SLACK_CLIENT_ID
|
- name: SLACK_CLIENT_ID
|
||||||
display_title: 'Slack Client ID'
|
display_title: 'Slack Client ID'
|
||||||
@@ -360,3 +341,17 @@
|
|||||||
value: 'v22.0'
|
value: 'v22.0'
|
||||||
locked: true
|
locked: true
|
||||||
# ------- End of Instagram Channel Related Config ------- #
|
# ------- End of Instagram Channel Related Config ------- #
|
||||||
|
|
||||||
|
## ------ Configs added for GitHub ------ ##
|
||||||
|
- name: GITHUB_CLIENT_ID
|
||||||
|
display_title: 'GitHub Client ID'
|
||||||
|
value:
|
||||||
|
locked: false
|
||||||
|
description: 'GitHub OAuth app client ID'
|
||||||
|
- name: GITHUB_CLIENT_SECRET
|
||||||
|
display_title: 'GitHub Client Secret'
|
||||||
|
value:
|
||||||
|
locked: false
|
||||||
|
description: 'GitHub OAuth app client secret'
|
||||||
|
type: secret
|
||||||
|
## ------ End of Configs added for GitHub ------ ##
|
||||||
|
|||||||
@@ -63,12 +63,6 @@ linear:
|
|||||||
action: https://linear.app/oauth/authorize
|
action: https://linear.app/oauth/authorize
|
||||||
hook_type: account
|
hook_type: account
|
||||||
allow_multiple_hooks: false
|
allow_multiple_hooks: false
|
||||||
notion:
|
|
||||||
id: notion
|
|
||||||
logo: notion.png
|
|
||||||
i18n_key: notion
|
|
||||||
hook_type: account
|
|
||||||
allow_multiple_hooks: false
|
|
||||||
slack:
|
slack:
|
||||||
id: slack
|
id: slack
|
||||||
logo: slack.png
|
logo: slack.png
|
||||||
@@ -284,3 +278,10 @@ leadsquared:
|
|||||||
'conversation_activity_score',
|
'conversation_activity_score',
|
||||||
'transcript_activity_score',
|
'transcript_activity_score',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
github:
|
||||||
|
id: github
|
||||||
|
logo: github.png
|
||||||
|
i18n_key: github
|
||||||
|
hook_type: account
|
||||||
|
allow_multiple_hooks: false
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ am:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Resolution Count
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ am:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ am:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ ar:
|
|||||||
conversations_count: عدد المحادثات
|
conversations_count: عدد المحادثات
|
||||||
avg_first_response_time: متوسط وقت الرد الأول
|
avg_first_response_time: متوسط وقت الرد الأول
|
||||||
avg_resolution_time: متوسط وقت الحل
|
avg_resolution_time: متوسط وقت الحل
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: عدد مرات الإغلاق
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: اسم الفريق
|
team_name: اسم الفريق
|
||||||
conversations_count: عدد المحادثات
|
conversations_count: عدد المحادثات
|
||||||
@@ -140,8 +138,6 @@ ar:
|
|||||||
instagram_story_content: 'أشار %{story_sender} إليك في القصة: '
|
instagram_story_content: 'أشار %{story_sender} إليك في القصة: '
|
||||||
instagram_deleted_story_content: هذه القصة لم تعد متاحة.
|
instagram_deleted_story_content: هذه القصة لم تعد متاحة.
|
||||||
deleted: تم حذف هذه الرسالة
|
deleted: تم حذف هذه الرسالة
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'رمز الخطأ: %{error_code}'
|
error_code: 'رمز الخطأ: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ ar:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} أضاف سياسة مستوى الخدمة %{sla_name}'
|
added: '%{user_name} أضاف سياسة مستوى الخدمة %{sla_name}'
|
||||||
removed: '%{user_name} أزال سياسة مستوى الخدمة %{sla_name}'
|
removed: '%{user_name} أزال سياسة مستوى الخدمة %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} كتم صوت المحادثة'
|
muted: '%{user_name} كتم صوت المحادثة'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ az:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Resolution Count
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ az:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ az:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ bg:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Resolution Count
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ bg:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ bg:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ ca:
|
|||||||
conversations_count: Nre. de converses
|
conversations_count: Nre. de converses
|
||||||
avg_first_response_time: Temps mitjà de primera resposta
|
avg_first_response_time: Temps mitjà de primera resposta
|
||||||
avg_resolution_time: Temps mitjà de resolució
|
avg_resolution_time: Temps mitjà de resolució
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Total de resolucions
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Nom de l'equip
|
team_name: Nom de l'equip
|
||||||
conversations_count: Recompte de converses
|
conversations_count: Recompte de converses
|
||||||
@@ -140,8 +138,6 @@ ca:
|
|||||||
instagram_story_content: '%{story_sender} t''ha mencionat a la història: '
|
instagram_story_content: '%{story_sender} t''ha mencionat a la història: '
|
||||||
instagram_deleted_story_content: Aquesta història ja no està disponible.
|
instagram_deleted_story_content: Aquesta història ja no està disponible.
|
||||||
deleted: Aquest missatge a sigut eliminat
|
deleted: Aquest missatge a sigut eliminat
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Codi d''error: %{error_code}'
|
error_code: 'Codi d''error: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ ca:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} ha afegit la política de SLA %{sla_name}'
|
added: '%{user_name} ha afegit la política de SLA %{sla_name}'
|
||||||
removed: '%{user_name} ha eliminat la política de SLA %{sla_name}'
|
removed: '%{user_name} ha eliminat la política de SLA %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} ha silenciat la conversa'
|
muted: '%{user_name} ha silenciat la conversa'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ cs:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Počet rozlišení
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ cs:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: Tato zpráva byla smazána
|
deleted: Tato zpráva byla smazána
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ cs:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} ztlumil/a konverzaci'
|
muted: '%{user_name} ztlumil/a konverzaci'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ da:
|
|||||||
conversations_count: Antal samtaler
|
conversations_count: Antal samtaler
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Antal Afsluttede
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team navn
|
team_name: Team navn
|
||||||
conversations_count: Samtaler tæller
|
conversations_count: Samtaler tæller
|
||||||
@@ -140,8 +138,6 @@ da:
|
|||||||
instagram_story_content: '%{story_sender} nævnte dig i historien: '
|
instagram_story_content: '%{story_sender} nævnte dig i historien: '
|
||||||
instagram_deleted_story_content: Denne historie er ikke længere tilgængelig.
|
instagram_deleted_story_content: Denne historie er ikke længere tilgængelig.
|
||||||
deleted: Denne besked blev slettet
|
deleted: Denne besked blev slettet
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ da:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} har slukket for samtalen'
|
muted: '%{user_name} har slukket for samtalen'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ de:
|
|||||||
conversations_count: Anzahl der Konversationen
|
conversations_count: Anzahl der Konversationen
|
||||||
avg_first_response_time: Durchschnittliche Zeit bis zur ersten Antwort
|
avg_first_response_time: Durchschnittliche Zeit bis zur ersten Antwort
|
||||||
avg_resolution_time: Durchschnittliche Auflösung
|
avg_resolution_time: Durchschnittliche Auflösung
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Auflösungsanzahl
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Teamname
|
team_name: Teamname
|
||||||
conversations_count: Anzahl Gespräche
|
conversations_count: Anzahl Gespräche
|
||||||
@@ -140,8 +138,6 @@ de:
|
|||||||
instagram_story_content: '%{story_sender} erwähnte sie in der Geschichte: '
|
instagram_story_content: '%{story_sender} erwähnte sie in der Geschichte: '
|
||||||
instagram_deleted_story_content: Diese Geschichte ist nicht mehr verfügbar.
|
instagram_deleted_story_content: Diese Geschichte ist nicht mehr verfügbar.
|
||||||
deleted: Diese Nachricht wurde gelöscht
|
deleted: Diese Nachricht wurde gelöscht
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Fehlercode: %{error_code}'
|
error_code: 'Fehlercode: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ de:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} hat SLA-Richtlinie %{sla_name} hinzugefügt'
|
added: '%{user_name} hat SLA-Richtlinie %{sla_name} hinzugefügt'
|
||||||
removed: '%{user_name} hat SLA-Richtlinie %{sla_name} entfernt'
|
removed: '%{user_name} hat SLA-Richtlinie %{sla_name} entfernt'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} hat das Gespräch stumm geschaltet'
|
muted: '%{user_name} hat das Gespräch stumm geschaltet'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ el:
|
|||||||
conversations_count: Αριθμός συνομιλιών
|
conversations_count: Αριθμός συνομιλιών
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Αριθμός Αναλύσεων
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Όνομα ομάδας
|
team_name: Όνομα ομάδας
|
||||||
conversations_count: Αριθμός συνομιλιών
|
conversations_count: Αριθμός συνομιλιών
|
||||||
@@ -140,8 +138,6 @@ el:
|
|||||||
instagram_story_content: 'Ο %{story_sender} σας ανέφερε στην ιστορία: '
|
instagram_story_content: 'Ο %{story_sender} σας ανέφερε στην ιστορία: '
|
||||||
instagram_deleted_story_content: Η ιστορία δεν είναι πλέον διαθέσιμη.
|
instagram_deleted_story_content: Η ιστορία δεν είναι πλέον διαθέσιμη.
|
||||||
deleted: Το μήνυμα διαγράφηκε
|
deleted: Το μήνυμα διαγράφηκε
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ el:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: 'Ο χρήστης %{user_name} σίγασε την συνομιλία'
|
muted: 'Ο χρήστης %{user_name} σίγασε την συνομιλία'
|
||||||
|
|||||||
+4
-12
@@ -105,8 +105,6 @@ en:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Resolution Count
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -190,14 +188,8 @@ en:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
auto_resolve:
|
|
||||||
not_sent_due_to_messaging_window: 'Auto-resolve message not sent due to outgoing message restrictions'
|
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
unmuted: '%{user_name} has unmuted the conversation'
|
unmuted: '%{user_name} has unmuted the conversation'
|
||||||
auto_resolution_message: 'Resolving the conversation as it has been inactive for a while. Please start a new conversation if you need further assistance.'
|
auto_resolution_message: 'Resolving the conversation as it has been inactive for a while. Please start a new conversation if you need further assistance.'
|
||||||
@@ -257,10 +249,6 @@ en:
|
|||||||
name: 'Linear'
|
name: 'Linear'
|
||||||
short_description: 'Create and link Linear issues directly from conversations.'
|
short_description: 'Create and link Linear issues directly from conversations.'
|
||||||
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
|
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
|
||||||
notion:
|
|
||||||
name: 'Notion'
|
|
||||||
short_description: 'Integrate databases, documents and pages directly with Captain.'
|
|
||||||
description: 'Connect your Notion workspace to enable Captain to access and generate intelligent responses using content from your databases, documents, and pages to provide more contextual customer support.'
|
|
||||||
shopify:
|
shopify:
|
||||||
name: 'Shopify'
|
name: 'Shopify'
|
||||||
short_description: 'Access order details and customer data from your Shopify store.'
|
short_description: 'Access order details and customer data from your Shopify store.'
|
||||||
@@ -269,6 +257,10 @@ en:
|
|||||||
name: 'LeadSquared'
|
name: 'LeadSquared'
|
||||||
short_description: 'Sync your contacts and conversations with LeadSquared CRM.'
|
short_description: 'Sync your contacts and conversations with LeadSquared CRM.'
|
||||||
description: 'Sync your contacts and conversations with LeadSquared CRM. This integration automatically creates leads in LeadSquared when new contacts are added, and logs conversation activity to provide your sales team with complete context.'
|
description: 'Sync your contacts and conversations with LeadSquared CRM. This integration automatically creates leads in LeadSquared when new contacts are added, and logs conversation activity to provide your sales team with complete context.'
|
||||||
|
github:
|
||||||
|
name: 'GitHub'
|
||||||
|
short_description: 'Create and manage GitHub issues directly from conversations.'
|
||||||
|
description: 'Connect your GitHub repositories to create issues directly from customer conversations. This integration helps you track bugs, feature requests, and development tasks seamlessly.'
|
||||||
captain:
|
captain:
|
||||||
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
|
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
|
||||||
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
|
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ es:
|
|||||||
conversations_count: Núm. de conversaciones
|
conversations_count: Núm. de conversaciones
|
||||||
avg_first_response_time: Promedio de tiempo de la primera respuesta
|
avg_first_response_time: Promedio de tiempo de la primera respuesta
|
||||||
avg_resolution_time: Tiempo promedio de resolución
|
avg_resolution_time: Tiempo promedio de resolución
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Número de resoluciones
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Nombre del equipo
|
team_name: Nombre del equipo
|
||||||
conversations_count: Cantidad de conversaciones
|
conversations_count: Cantidad de conversaciones
|
||||||
@@ -140,8 +138,6 @@ es:
|
|||||||
instagram_story_content: '%{story_sender} te mencionó en la historia: '
|
instagram_story_content: '%{story_sender} te mencionó en la historia: '
|
||||||
instagram_deleted_story_content: Esta historia ya no está disponible.
|
instagram_deleted_story_content: Esta historia ya no está disponible.
|
||||||
deleted: Este mensaje se ha eliminado
|
deleted: Este mensaje se ha eliminado
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Código de error: %{error_code}'
|
error_code: 'Código de error: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ es:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} agregó la política de SLA %{sla_name}'
|
added: '%{user_name} agregó la política de SLA %{sla_name}'
|
||||||
removed: '%{user_name} eliminó la política de SLA %{sla_name}'
|
removed: '%{user_name} eliminó la política de SLA %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} ha silenciado la conversación'
|
muted: '%{user_name} ha silenciado la conversación'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ fa:
|
|||||||
conversations_count: تعداد گفتگوها
|
conversations_count: تعداد گفتگوها
|
||||||
avg_first_response_time: میانگین زمان تا اولین پاسخ
|
avg_first_response_time: میانگین زمان تا اولین پاسخ
|
||||||
avg_resolution_time: میانگین زمان حل مشکل
|
avg_resolution_time: میانگین زمان حل مشکل
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: تعداد مسائل حل شده
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: نام تیم
|
team_name: نام تیم
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ fa:
|
|||||||
instagram_story_content: '%{story_sender} در داستان به شما اشاره کرده: '
|
instagram_story_content: '%{story_sender} در داستان به شما اشاره کرده: '
|
||||||
instagram_deleted_story_content: این داستان دیگر در دسترس نیست.
|
instagram_deleted_story_content: این داستان دیگر در دسترس نیست.
|
||||||
deleted: این پیام حذف شد
|
deleted: این پیام حذف شد
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'کد خطا " %{error_code}'
|
error_code: 'کد خطا " %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ fa:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} سیاست SLA %{sla_name} را اضافه کرد'
|
added: '%{user_name} سیاست SLA %{sla_name} را اضافه کرد'
|
||||||
removed: '%{user_name} سیاست SLA %{sla_name} را حذف کرد'
|
removed: '%{user_name} سیاست SLA %{sla_name} را حذف کرد'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} مکالمه را بی صدا کرد'
|
muted: '%{user_name} مکالمه را بی صدا کرد'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ fi:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Selvitysmäärä
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ fi:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ fi:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} mykisti keskustelun'
|
muted: '%{user_name} mykisti keskustelun'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ fr:
|
|||||||
conversations_count: Nbre de conversations
|
conversations_count: Nbre de conversations
|
||||||
avg_first_response_time: Temps moyen pour une première réponse
|
avg_first_response_time: Temps moyen pour une première réponse
|
||||||
avg_resolution_time: Temps nécessaire pour résoudre une demande (en moyenne)
|
avg_resolution_time: Temps nécessaire pour résoudre une demande (en moyenne)
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Nombre de résolutions
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Nom de l'équipe
|
team_name: Nom de l'équipe
|
||||||
conversations_count: Nombre de conversations
|
conversations_count: Nombre de conversations
|
||||||
@@ -140,8 +138,6 @@ fr:
|
|||||||
instagram_story_content: '%{story_sender} vous a mentionné dans la story: '
|
instagram_story_content: '%{story_sender} vous a mentionné dans la story: '
|
||||||
instagram_deleted_story_content: Cette Story n'est plus disponible.
|
instagram_deleted_story_content: Cette Story n'est plus disponible.
|
||||||
deleted: Ce message a été supprimé
|
deleted: Ce message a été supprimé
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Code d''erreur : %{error_code}'
|
error_code: 'Code d''erreur : %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ fr:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} a mis la conversation en sourdine'
|
muted: '%{user_name} a mis la conversation en sourdine'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ he:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: ספירת רזולוציות
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: שם קבוצה
|
team_name: שם קבוצה
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ he:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ he:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ hi:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Resolution Count
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ hi:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ hi:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ hr:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Resolution Count
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ hr:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ hr:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ hu:
|
|||||||
conversations_count: Beszélgetések száma
|
conversations_count: Beszélgetések száma
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Megoldások száma
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Csapatnév
|
team_name: Csapatnév
|
||||||
conversations_count: Beszélgetésszám
|
conversations_count: Beszélgetésszám
|
||||||
@@ -140,8 +138,6 @@ hu:
|
|||||||
instagram_story_content: '%{story_sender} megemlített egy storyban: '
|
instagram_story_content: '%{story_sender} megemlített egy storyban: '
|
||||||
instagram_deleted_story_content: Ez a story már nem érhető el.
|
instagram_deleted_story_content: Ez a story már nem érhető el.
|
||||||
deleted: Az üzenet törölve lett
|
deleted: Az üzenet törölve lett
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Hibakód: %{error_code}'
|
error_code: 'Hibakód: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ hu:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} elnémította a beszélgetést'
|
muted: '%{user_name} elnémította a beszélgetést'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ hy:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Resolution Count
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ hy:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ hy:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ id:
|
|||||||
conversations_count: Jumlah percakapan
|
conversations_count: Jumlah percakapan
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Jumlah Terselesaikan
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Nama Tim
|
team_name: Nama Tim
|
||||||
conversations_count: Jumlah percakapan
|
conversations_count: Jumlah percakapan
|
||||||
@@ -140,8 +138,6 @@ id:
|
|||||||
instagram_story_content: '%{story_sender} menyebutmu dalam story: '
|
instagram_story_content: '%{story_sender} menyebutmu dalam story: '
|
||||||
instagram_deleted_story_content: Story ini tidak lagi tersedia.
|
instagram_deleted_story_content: Story ini tidak lagi tersedia.
|
||||||
deleted: Pesan ini telah terhapus
|
deleted: Pesan ini telah terhapus
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ id:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} me-mute percakapan'
|
muted: '%{user_name} me-mute percakapan'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ is:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Resolution Count
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ is:
|
|||||||
instagram_story_content: '%{story_sender} minntist á þig í sögunni: '
|
instagram_story_content: '%{story_sender} minntist á þig í sögunni: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ is:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ it:
|
|||||||
conversations_count: Numero di conversazioni
|
conversations_count: Numero di conversazioni
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Conteggio risoluzioni
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Nome del team
|
team_name: Nome del team
|
||||||
conversations_count: Numero di conversazioni
|
conversations_count: Numero di conversazioni
|
||||||
@@ -140,8 +138,6 @@ it:
|
|||||||
instagram_story_content: '%{story_sender} ti ha menzionato nella storia: '
|
instagram_story_content: '%{story_sender} ti ha menzionato nella storia: '
|
||||||
instagram_deleted_story_content: Questa storia non è più disponibile.
|
instagram_deleted_story_content: Questa storia non è più disponibile.
|
||||||
deleted: Questo messaggio è stato eliminato
|
deleted: Questo messaggio è stato eliminato
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ it:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} ha silenziato la conversazione'
|
muted: '%{user_name} ha silenziato la conversazione'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ ja:
|
|||||||
conversations_count: 会話数
|
conversations_count: 会話数
|
||||||
avg_first_response_time: 初回応答の平均時間
|
avg_first_response_time: 初回応答の平均時間
|
||||||
avg_resolution_time: 解決までの平均時間
|
avg_resolution_time: 解決までの平均時間
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: 処理件数
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: チーム名
|
team_name: チーム名
|
||||||
conversations_count: 会話回数
|
conversations_count: 会話回数
|
||||||
@@ -140,8 +138,6 @@ ja:
|
|||||||
instagram_story_content: '%{story_sender} さんがストーリーであなたについて言及しました: '
|
instagram_story_content: '%{story_sender} さんがストーリーであなたについて言及しました: '
|
||||||
instagram_deleted_story_content: このストーリーはもう利用できません。
|
instagram_deleted_story_content: このストーリーはもう利用できません。
|
||||||
deleted: このメッセージは削除されました
|
deleted: このメッセージは削除されました
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'エラーコード: %{error_code}'
|
error_code: 'エラーコード: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ ja:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} がSLAポリシー "%{sla_name}" を追加しました'
|
added: '%{user_name} がSLAポリシー "%{sla_name}" を追加しました'
|
||||||
removed: '%{user_name} がSLAポリシー "%{sla_name}" を削除しました'
|
removed: '%{user_name} がSLAポリシー "%{sla_name}" を削除しました'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} が会話をミュートしました'
|
muted: '%{user_name} が会話をミュートしました'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ ka:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Resolution Count
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ ka:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ ka:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ ko:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: 해결 수
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ ko:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ ko:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ lt:
|
|||||||
conversations_count: Pokalbių kiekis
|
conversations_count: Pokalbių kiekis
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Sprendimų skaičius
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Komandos pavadinimas
|
team_name: Komandos pavadinimas
|
||||||
conversations_count: Pokalbių skaičius
|
conversations_count: Pokalbių skaičius
|
||||||
@@ -140,8 +138,6 @@ lt:
|
|||||||
instagram_story_content: '%{story_sender} paminėjo jus pasakojime: '
|
instagram_story_content: '%{story_sender} paminėjo jus pasakojime: '
|
||||||
instagram_deleted_story_content: Šis pasakojimas nebepasiekiamas.
|
instagram_deleted_story_content: Šis pasakojimas nebepasiekiamas.
|
||||||
deleted: Šis pranešimas buvo ištrintas
|
deleted: Šis pranešimas buvo ištrintas
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Klaidos kodas: %{error_code}'
|
error_code: 'Klaidos kodas: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ lt:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} nutildė pokalbį'
|
muted: '%{user_name} nutildė pokalbį'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ lv:
|
|||||||
conversations_count: Sarunu skaits
|
conversations_count: Sarunu skaits
|
||||||
avg_first_response_time: Vidējais pirmās reakcijas laiks
|
avg_first_response_time: Vidējais pirmās reakcijas laiks
|
||||||
avg_resolution_time: Vidējais atrisināšanas laiks
|
avg_resolution_time: Vidējais atrisināšanas laiks
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Atrisināšanas Skaits
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Komandas nosaukums
|
team_name: Komandas nosaukums
|
||||||
conversations_count: Sarunu skaits
|
conversations_count: Sarunu skaits
|
||||||
@@ -140,8 +138,6 @@ lv:
|
|||||||
instagram_story_content: '%{story_sender} pieminēja jūs stāstā: '
|
instagram_story_content: '%{story_sender} pieminēja jūs stāstā: '
|
||||||
instagram_deleted_story_content: Šis stāsts vairs nav pieejams.
|
instagram_deleted_story_content: Šis stāsts vairs nav pieejams.
|
||||||
deleted: Šis ziņojums ir izdzēsts
|
deleted: Šis ziņojums ir izdzēsts
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Kļūdas kods: %{error_code}'
|
error_code: 'Kļūdas kods: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ lv:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} pievienoja SLA politiku %{sla_name}'
|
added: '%{user_name} pievienoja SLA politiku %{sla_name}'
|
||||||
removed: '%{user_name} noņēma SLA politiku %{sla_name}'
|
removed: '%{user_name} noņēma SLA politiku %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} izslēdza sarunu'
|
muted: '%{user_name} izslēdza sarunu'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ ml:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: മിഴിവ് എണ്ണം
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: ടീമിന്റെ പേര്
|
team_name: ടീമിന്റെ പേര്
|
||||||
conversations_count: സംഭാഷണങ്ങളുടെ എണ്ണം
|
conversations_count: സംഭാഷണങ്ങളുടെ എണ്ണം
|
||||||
@@ -140,8 +138,6 @@ ml:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: ഈ സന്ദേശം ഇല്ലാതാക്കി
|
deleted: ഈ സന്ദേശം ഇല്ലാതാക്കി
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ ml:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ ms:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Resolution Count
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ ms:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ ms:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
@@ -91,8 +91,6 @@ ne:
|
|||||||
conversations_count: No. of conversations
|
conversations_count: No. of conversations
|
||||||
avg_first_response_time: Avg first response time
|
avg_first_response_time: Avg first response time
|
||||||
avg_resolution_time: Avg resolution time
|
avg_resolution_time: Avg resolution time
|
||||||
avg_reply_time: Avg reply time
|
|
||||||
resolution_count: Resolution Count
|
|
||||||
team_csv:
|
team_csv:
|
||||||
team_name: Team name
|
team_name: Team name
|
||||||
conversations_count: Conversations count
|
conversations_count: Conversations count
|
||||||
@@ -140,8 +138,6 @@ ne:
|
|||||||
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
instagram_story_content: '%{story_sender} mentioned you in the story: '
|
||||||
instagram_deleted_story_content: This story is no longer available.
|
instagram_deleted_story_content: This story is no longer available.
|
||||||
deleted: This message was deleted
|
deleted: This message was deleted
|
||||||
whatsapp:
|
|
||||||
list_button_label: 'Choose an item'
|
|
||||||
delivery_status:
|
delivery_status:
|
||||||
error_code: 'Error code: %{error_code}'
|
error_code: 'Error code: %{error_code}'
|
||||||
activity:
|
activity:
|
||||||
@@ -176,10 +172,6 @@ ne:
|
|||||||
sla:
|
sla:
|
||||||
added: '%{user_name} added SLA policy %{sla_name}'
|
added: '%{user_name} added SLA policy %{sla_name}'
|
||||||
removed: '%{user_name} removed SLA policy %{sla_name}'
|
removed: '%{user_name} removed SLA policy %{sla_name}'
|
||||||
linear:
|
|
||||||
issue_created: 'Linear issue %{issue_id} was created by %{user_name}'
|
|
||||||
issue_linked: 'Linear issue %{issue_id} was linked by %{user_name}'
|
|
||||||
issue_unlinked: 'Linear issue %{issue_id} was unlinked by %{user_name}'
|
|
||||||
csat:
|
csat:
|
||||||
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
not_sent_due_to_messaging_window: 'CSAT survey not sent due to outgoing message restrictions'
|
||||||
muted: '%{user_name} has muted the conversation'
|
muted: '%{user_name} has muted the conversation'
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user