Compare commits
63
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be2d8e52cb | ||
|
|
a940f4c1d2 | ||
|
|
e819f7ee92 | ||
|
|
5b4f92ccd2 | ||
|
|
72022c263e | ||
|
|
ad03be4529 | ||
|
|
571e6bd0ec | ||
|
|
6b2171f6aa | ||
|
|
b698a332e0 | ||
|
|
528da1d2cf | ||
|
|
4e8d17f017 | ||
|
|
3054a4cb59 | ||
|
|
92aecb1262 | ||
|
|
be028dbedc | ||
|
|
acf19bc70d | ||
|
|
e8d0f14554 | ||
|
|
71837bedf9 | ||
|
|
3c4514c9f7 | ||
|
|
4c7c1cd78a | ||
|
|
985b3f3bfc | ||
|
|
986abde531 | ||
|
|
587db31cdd | ||
|
|
8f0b4e1b58 | ||
|
|
c5dd246071 | ||
|
|
4cdf28860a | ||
|
|
e3aef4a778 | ||
|
|
b57063a8b8 | ||
|
|
870e3716d9 | ||
|
|
e62f74bb80 | ||
|
|
9d1ee2d506 | ||
|
|
a622041696 | ||
|
|
18245dd757 | ||
|
|
022f4f899f | ||
|
|
191b8a64fe | ||
|
|
ea78020f2f | ||
|
|
dc1a41b136 | ||
|
|
0ddf241d7f | ||
|
|
99dc6a0eb3 | ||
|
|
3be125ea66 | ||
|
|
5af2f541a1 | ||
|
|
908db4df5e | ||
|
|
28e7a5d228 | ||
|
|
40830046e8 | ||
|
|
d05c953eef | ||
|
|
4a770fdea7 | ||
|
|
239b1e2bf1 | ||
|
|
f963e00731 | ||
|
|
155a5b9947 | ||
|
|
26a75b250d | ||
|
|
20b84ee6a1 | ||
|
|
f1f14312fe | ||
|
|
212d7caab1 | ||
|
|
9cda16d0e8 | ||
|
|
a8acbb7427 | ||
|
|
1176e5eb8a | ||
|
|
996325f35b | ||
|
|
4f8ce7b597 | ||
|
|
f8e631a00c | ||
|
|
54bf33083e | ||
|
|
533f9f7fe4 | ||
|
|
82e5fc413e | ||
|
|
93daaea19b | ||
|
|
e6a49b5800 |
+18
-18
@@ -73,7 +73,7 @@ jobs:
|
||||
|
||||
- run:
|
||||
name: yarn
|
||||
command: yarn install --cache-folder ~/.cache/yarn
|
||||
command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
|
||||
|
||||
# Store yarn / webpacker cache
|
||||
- save_cache:
|
||||
@@ -104,9 +104,8 @@ jobs:
|
||||
fi
|
||||
curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/6.3.0/openapi-generator-cli-6.3.0.jar > ~/tmp/openapi-generator-cli-6.3.0.jar
|
||||
java -jar ~/tmp/openapi-generator-cli-6.3.0.jar validate -i swagger/swagger.json
|
||||
|
||||
|
||||
# Database setup
|
||||
- run: yarn install --check-files
|
||||
- run: bundle exec rake db:create
|
||||
- run: bundle exec rake db:schema:load
|
||||
|
||||
@@ -117,7 +116,7 @@ jobs:
|
||||
- run:
|
||||
name: Rubocop
|
||||
command: bundle exec rubocop
|
||||
|
||||
|
||||
# - run:
|
||||
# name: Brakeman
|
||||
# command: bundle exec brakeman
|
||||
@@ -126,6 +125,21 @@ jobs:
|
||||
name: eslint
|
||||
command: yarn run eslint
|
||||
|
||||
# Run frontend tests
|
||||
- run:
|
||||
name: Run frontend tests
|
||||
command: |
|
||||
mkdir -p ~/tmp/test-results/frontend_specs
|
||||
~/tmp/cc-test-reporter before-build
|
||||
TESTFILES=$(circleci tests glob **/specs/*.spec.js | circleci tests split --split-by=timings)
|
||||
yarn test:coverage --profile 10 \
|
||||
--out ~/tmp/test-results/yarn.xml \
|
||||
-- ${TESTFILES}
|
||||
- run:
|
||||
name: Code Climate Test Coverage
|
||||
command: |
|
||||
~/tmp/cc-test-reporter format-coverage -t lcov -o "coverage/codeclimate.frontend_$CIRCLE_NODE_INDEX.json"
|
||||
|
||||
# Run rails tests
|
||||
- run:
|
||||
name: Run backend tests
|
||||
@@ -145,20 +159,6 @@ jobs:
|
||||
command: |
|
||||
~/tmp/cc-test-reporter format-coverage -t simplecov -o "coverage/codeclimate.$CIRCLE_NODE_INDEX.json"
|
||||
|
||||
- run:
|
||||
name: Run frontend tests
|
||||
command: |
|
||||
mkdir -p ~/tmp/test-results/frontend_specs
|
||||
~/tmp/cc-test-reporter before-build
|
||||
TESTFILES=$(circleci tests glob **/specs/*.spec.js | circleci tests split --split-by=timings)
|
||||
yarn test:coverage --profile 10 \
|
||||
--out ~/tmp/test-results/yarn.xml \
|
||||
-- ${TESTFILES}
|
||||
- run:
|
||||
name: Code Climate Test Coverage
|
||||
command: |
|
||||
~/tmp/cc-test-reporter format-coverage -t lcov -o "coverage/codeclimate.frontend_$CIRCLE_NODE_INDEX.json"
|
||||
|
||||
- persist_to_workspace:
|
||||
root: coverage
|
||||
paths:
|
||||
|
||||
@@ -74,3 +74,5 @@ yalc.lock
|
||||
/yarn-error.log
|
||||
yarn-debug.log*
|
||||
.yarn-integrity
|
||||
|
||||
/storybook-static
|
||||
@@ -4,7 +4,7 @@ ruby '3.2.2'
|
||||
|
||||
##-- base gems for rails --##
|
||||
gem 'rack-cors', require: 'rack/cors'
|
||||
gem 'rails', '~> 7'
|
||||
gem 'rails', '~> 7.0.5.1'
|
||||
# Reduces boot times through caching; required in config/boot.rb
|
||||
gem 'bootsnap', require: false
|
||||
|
||||
|
||||
+58
-58
@@ -33,70 +33,70 @@ GIT
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
actioncable (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
actionmailbox (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
activejob (= 7.0.5)
|
||||
activerecord (= 7.0.5)
|
||||
activestorage (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
actionmailbox (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
activejob (= 7.0.5.1)
|
||||
activerecord (= 7.0.5.1)
|
||||
activestorage (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
mail (>= 2.7.1)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
actionmailer (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
actionview (= 7.0.5)
|
||||
activejob (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
actionmailer (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
actionview (= 7.0.5.1)
|
||||
activejob (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (7.0.5)
|
||||
actionview (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
actionpack (7.0.5.1)
|
||||
actionview (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
rack (~> 2.0, >= 2.2.4)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
actiontext (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
activerecord (= 7.0.5)
|
||||
activestorage (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
actiontext (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
activerecord (= 7.0.5.1)
|
||||
activestorage (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
actionview (7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||
active_record_query_trace (1.8)
|
||||
activejob (7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
activejob (7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
activerecord (7.0.5)
|
||||
activemodel (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
activemodel (7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
activerecord (7.0.5.1)
|
||||
activemodel (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
activerecord-import (1.4.1)
|
||||
activerecord (>= 4.2)
|
||||
activestorage (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
activejob (= 7.0.5)
|
||||
activerecord (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
activestorage (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
activejob (= 7.0.5.1)
|
||||
activerecord (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
marcel (~> 1.0)
|
||||
mini_mime (>= 1.1.0)
|
||||
activesupport (7.0.5)
|
||||
activesupport (7.0.5.1)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
@@ -441,7 +441,7 @@ GEM
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.2)
|
||||
mini_portile2 (2.8.2)
|
||||
minitest (5.18.0)
|
||||
minitest (5.18.1)
|
||||
mock_redis (0.36.0)
|
||||
ruby2_keywords
|
||||
msgpack (1.7.0)
|
||||
@@ -450,7 +450,7 @@ GEM
|
||||
multipart-post (2.3.0)
|
||||
net-http-persistent (4.0.2)
|
||||
connection_pool (~> 2.2)
|
||||
net-imap (0.3.4)
|
||||
net-imap (0.3.6)
|
||||
date
|
||||
net-protocol
|
||||
net-pop (0.1.2)
|
||||
@@ -525,7 +525,7 @@ GEM
|
||||
pundit (2.3.0)
|
||||
activesupport (>= 3.0.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.7.0)
|
||||
racc (1.7.1)
|
||||
rack (2.2.7)
|
||||
rack-attack (6.6.1)
|
||||
rack (>= 1.0, < 3)
|
||||
@@ -540,29 +540,29 @@ GEM
|
||||
rack-test (2.1.0)
|
||||
rack (>= 1.3)
|
||||
rack-timeout (0.6.3)
|
||||
rails (7.0.5)
|
||||
actioncable (= 7.0.5)
|
||||
actionmailbox (= 7.0.5)
|
||||
actionmailer (= 7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
actiontext (= 7.0.5)
|
||||
actionview (= 7.0.5)
|
||||
activejob (= 7.0.5)
|
||||
activemodel (= 7.0.5)
|
||||
activerecord (= 7.0.5)
|
||||
activestorage (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
rails (7.0.5.1)
|
||||
actioncable (= 7.0.5.1)
|
||||
actionmailbox (= 7.0.5.1)
|
||||
actionmailer (= 7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
actiontext (= 7.0.5.1)
|
||||
actionview (= 7.0.5.1)
|
||||
activejob (= 7.0.5.1)
|
||||
activemodel (= 7.0.5.1)
|
||||
activerecord (= 7.0.5.1)
|
||||
activestorage (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 7.0.5)
|
||||
railties (= 7.0.5.1)
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.6.0)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (~> 1.14)
|
||||
railties (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
railties (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
method_source
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
@@ -731,7 +731,7 @@ GEM
|
||||
time_diff (0.3.0)
|
||||
activesupport
|
||||
i18n
|
||||
timeout (0.3.2)
|
||||
timeout (0.4.0)
|
||||
trailblazer-option (0.1.2)
|
||||
twilio-ruby (5.77.0)
|
||||
faraday (>= 0.9, < 3.0)
|
||||
@@ -875,7 +875,7 @@ DEPENDENCIES
|
||||
rack-cors
|
||||
rack-mini-profiler
|
||||
rack-timeout
|
||||
rails (~> 7)
|
||||
rails (~> 7.0.5.1)
|
||||
redis
|
||||
redis-namespace
|
||||
responders
|
||||
|
||||
@@ -11,7 +11,7 @@ function prepareData(data) {
|
||||
|
||||
function getChartOptions() {
|
||||
var fontFamily =
|
||||
'Inter,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
|
||||
'PlusJakarta,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
|
||||
return {
|
||||
responsive: true,
|
||||
legend: { labels: { fontFamily } },
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Typography
|
||||
$base-font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
||||
$base-font-family: PlusJakarta, Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif !default;
|
||||
$heading-font-family: $base-font-family !default;
|
||||
|
||||
$base-font-size: 10px !default;
|
||||
$base-font-size: 16px !default;
|
||||
|
||||
$base-line-height: 1.5 !default;
|
||||
$heading-line-height: 1.2 !default;
|
||||
|
||||
@@ -48,17 +48,22 @@ class Messages::MessageBuilder
|
||||
def process_emails
|
||||
return unless @conversation.inbox&.inbox_type == 'Email'
|
||||
|
||||
cc_emails = []
|
||||
cc_emails = @params[:cc_emails].gsub(/\s+/, '').split(',') if @params[:cc_emails].present?
|
||||
cc_emails = process_email_string(@params[:cc_emails])
|
||||
bcc_emails = process_email_string(@params[:bcc_emails])
|
||||
to_emails = process_email_string(@params[:to_emails])
|
||||
|
||||
bcc_emails = []
|
||||
bcc_emails = @params[:bcc_emails].gsub(/\s+/, '').split(',') if @params[:bcc_emails].present?
|
||||
|
||||
all_email_addresses = cc_emails + bcc_emails
|
||||
all_email_addresses = cc_emails + bcc_emails + to_emails
|
||||
validate_email_addresses(all_email_addresses)
|
||||
|
||||
@message.content_attributes[:cc_emails] = cc_emails
|
||||
@message.content_attributes[:bcc_emails] = bcc_emails
|
||||
@message.content_attributes[:to_emails] = to_emails
|
||||
end
|
||||
|
||||
def process_email_string(email_string)
|
||||
return [] if email_string.blank?
|
||||
|
||||
email_string.gsub(/\s+/, '').split(',')
|
||||
end
|
||||
|
||||
def validate_email_addresses(all_emails)
|
||||
|
||||
@@ -63,7 +63,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||
end
|
||||
|
||||
def destroy
|
||||
::DeleteObjectJob.perform_later(@inbox) if @inbox.present?
|
||||
::DeleteObjectJob.perform_later(@inbox, Current.user, request.ip) if @inbox.present?
|
||||
render status: :ok, json: { message: I18n.t('messages.inbox_deletetion_response') }
|
||||
end
|
||||
|
||||
@@ -124,7 +124,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||
def inbox_attributes
|
||||
[:name, :avatar, :greeting_enabled, :greeting_message, :enable_email_collect, :csat_survey_enabled,
|
||||
:enable_auto_assignment, :working_hours_enabled, :out_of_office_message, :timezone, :allow_messages_after_resolved,
|
||||
:lock_to_single_conversation, :portal_id]
|
||||
:lock_to_single_conversation, :portal_id, :sender_name_type, :business_name]
|
||||
end
|
||||
|
||||
def permitted_params(channel_attributes = [])
|
||||
|
||||
@@ -17,7 +17,8 @@ class Api::V1::Widget::MessagesController < Api::V1::Widget::BaseController
|
||||
@message.update!(submitted_email: contact_email)
|
||||
ContactIdentifyAction.new(
|
||||
contact: @contact,
|
||||
params: { email: contact_email, name: contact_name }
|
||||
params: { email: contact_email, name: contact_name },
|
||||
retain_original_contact_name: true
|
||||
).perform
|
||||
else
|
||||
@message.update!(message_update_params[:message])
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
class DashboardController < ActionController::Base
|
||||
include SwitchLocale
|
||||
|
||||
before_action :set_application_pack
|
||||
before_action :set_global_config
|
||||
around_action :switch_locale
|
||||
before_action :ensure_installation_onboarding, only: [:index]
|
||||
@@ -14,7 +15,7 @@ class DashboardController < ActionController::Base
|
||||
|
||||
def set_global_config
|
||||
@global_config = GlobalConfig.get(
|
||||
'LOGO', 'LOGO_THUMBNAIL',
|
||||
'LOGO', 'LOGO_DARK', 'LOGO_THUMBNAIL',
|
||||
'INSTALLATION_NAME',
|
||||
'WIDGET_BRAND_URL', 'TERMS_URL',
|
||||
'PRIVACY_URL',
|
||||
@@ -60,4 +61,12 @@ class DashboardController < ActionController::Base
|
||||
GIT_SHA: GIT_HASH
|
||||
}
|
||||
end
|
||||
|
||||
def set_application_pack
|
||||
@application_pack = if request.path.include?('/auth') || request.path.include?('/login')
|
||||
'v3app'
|
||||
else
|
||||
'application'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,7 +6,8 @@ class ConversationFinder
|
||||
latest: 'latest',
|
||||
sort_on_created_at: 'sort_on_created_at',
|
||||
last_user_message_at: 'last_user_message_at',
|
||||
sort_on_priority: 'sort_on_priority'
|
||||
sort_on_priority: 'sort_on_priority',
|
||||
sort_on_waiting_since: 'sort_on_waiting_since'
|
||||
}.with_indifferent_access
|
||||
|
||||
# assumptions
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
v-if="!authUIFlags.isFetching"
|
||||
id="app"
|
||||
class="app-wrapper app-root"
|
||||
:class="{ 'app-rtl--wrapper': isRTLView }"
|
||||
:class="{ 'app-rtl--wrapper': isRTLView, dark: theme === 'dark' }"
|
||||
:dir="isRTLView ? 'rtl' : 'ltr'"
|
||||
>
|
||||
<update-banner :latest-chatwoot-version="latestChatwootVersion" />
|
||||
<template v-if="!accountUIFlags.isFetchingItem && currentAccountId">
|
||||
@@ -34,10 +35,12 @@ import PaymentPendingBanner from './components/app/PaymentPendingBanner.vue';
|
||||
import vueActionCable from './helper/actionCable';
|
||||
import WootSnackbarBox from './components/SnackbarContainer';
|
||||
import rtlMixin from 'shared/mixins/rtlMixin';
|
||||
import { LocalStorage } from 'shared/helpers/localStorage';
|
||||
import {
|
||||
registerSubscription,
|
||||
verifyServiceWorkerExistence,
|
||||
} from './helper/pushHelper';
|
||||
import { LOCAL_STORAGE_KEYS } from './constants/localStorage';
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
@@ -58,6 +61,7 @@ export default {
|
||||
return {
|
||||
showAddAccountModal: false,
|
||||
latestChatwootVersion: null,
|
||||
theme: 'light',
|
||||
};
|
||||
},
|
||||
|
||||
@@ -89,9 +93,34 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.initializeColorTheme();
|
||||
this.listenToThemeChanges();
|
||||
this.setLocale(window.chatwootConfig.selectedLocale);
|
||||
},
|
||||
methods: {
|
||||
initializeColorTheme() {
|
||||
this.setColorTheme(
|
||||
window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
);
|
||||
},
|
||||
setColorTheme(isOSOnDarkMode) {
|
||||
const selectedColorScheme =
|
||||
LocalStorage.get(LOCAL_STORAGE_KEYS.COLOR_SCHEME) || 'light';
|
||||
if (
|
||||
(selectedColorScheme === 'auto' && isOSOnDarkMode) ||
|
||||
selectedColorScheme === 'dark'
|
||||
) {
|
||||
this.theme = 'dark';
|
||||
document.body.classList.add('dark');
|
||||
} else {
|
||||
this.theme = 'light ';
|
||||
document.body.classList.remove('dark');
|
||||
}
|
||||
},
|
||||
listenToThemeChanges() {
|
||||
const mql = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
mql.onchange = e => this.setColorTheme(e.matches);
|
||||
},
|
||||
setLocale(locale) {
|
||||
this.$root.$i18n.locale = locale;
|
||||
},
|
||||
|
||||
@@ -3,47 +3,11 @@
|
||||
import Cookies from 'js-cookie';
|
||||
import endPoints from './endPoints';
|
||||
import {
|
||||
setAuthCredentials,
|
||||
clearCookiesOnLogout,
|
||||
deleteIndexedDBOnLogout,
|
||||
} from '../store/utils/api';
|
||||
|
||||
export default {
|
||||
login(creds) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post('auth/sign_in', creds)
|
||||
.then(response => {
|
||||
setAuthCredentials(response);
|
||||
resolve(response.data);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error.response);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
register(creds) {
|
||||
const urlData = endPoints('register');
|
||||
const fetchPromise = new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post(urlData.url, {
|
||||
account_name: creds.accountName.trim(),
|
||||
user_full_name: creds.fullName.trim(),
|
||||
email: creds.email,
|
||||
password: creds.password,
|
||||
h_captcha_client_response: creds.hCaptchaClientResponse,
|
||||
})
|
||||
.then(response => {
|
||||
setAuthCredentials(response);
|
||||
resolve(response);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
return fetchPromise;
|
||||
},
|
||||
validityCheck() {
|
||||
const urlData = endPoints('validityCheck');
|
||||
return axios.get(urlData.url);
|
||||
@@ -73,45 +37,6 @@ export default {
|
||||
}
|
||||
return false;
|
||||
},
|
||||
verifyPasswordToken({ confirmationToken }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.post('auth/confirmation', {
|
||||
confirmation_token: confirmationToken,
|
||||
})
|
||||
.then(response => {
|
||||
setAuthCredentials(response);
|
||||
resolve(response);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error.response);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
setNewPassword({ resetPasswordToken, password, confirmPassword }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios
|
||||
.put('auth/password', {
|
||||
reset_password_token: resetPasswordToken,
|
||||
password_confirmation: confirmPassword,
|
||||
password,
|
||||
})
|
||||
.then(response => {
|
||||
setAuthCredentials(response);
|
||||
resolve(response);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error.response);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
resetPassword({ email }) {
|
||||
const urlData = endPoints('resetPassword');
|
||||
return axios.post(urlData.url, { email });
|
||||
},
|
||||
|
||||
profileUpdate({
|
||||
password,
|
||||
password_confirmation,
|
||||
|
||||
@@ -10,6 +10,7 @@ export const buildCreatePayload = ({
|
||||
files,
|
||||
ccEmails = '',
|
||||
bccEmails = '',
|
||||
toEmails = '',
|
||||
templateParams,
|
||||
}) => {
|
||||
let payload;
|
||||
@@ -25,6 +26,9 @@ export const buildCreatePayload = ({
|
||||
payload.append('echo_id', echoId);
|
||||
payload.append('cc_emails', ccEmails);
|
||||
payload.append('bcc_emails', bccEmails);
|
||||
if (toEmails) {
|
||||
payload.append('to_emails', toEmails);
|
||||
}
|
||||
} else {
|
||||
payload = {
|
||||
content: message,
|
||||
@@ -33,6 +37,7 @@ export const buildCreatePayload = ({
|
||||
content_attributes: contentAttributes,
|
||||
cc_emails: ccEmails,
|
||||
bcc_emails: bccEmails,
|
||||
to_emails: toEmails,
|
||||
template_params: templateParams,
|
||||
};
|
||||
}
|
||||
@@ -53,6 +58,7 @@ class MessageApi extends ApiClient {
|
||||
files,
|
||||
ccEmails = '',
|
||||
bccEmails = '',
|
||||
toEmails = '',
|
||||
templateParams,
|
||||
}) {
|
||||
return axios({
|
||||
@@ -66,6 +72,7 @@ class MessageApi extends ApiClient {
|
||||
files,
|
||||
ccEmails,
|
||||
bccEmails,
|
||||
toEmails,
|
||||
templateParams,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -2,18 +2,62 @@
|
||||
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
/**
|
||||
* Represents the data object for a OpenAI hook.
|
||||
* @typedef {Object} ConversationMessageData
|
||||
* @property {string} [tone] - The tone of the message.
|
||||
* @property {string} [content] - The content of the message.
|
||||
* @property {string} [conversation_display_id] - The display ID of the conversation (optional).
|
||||
*/
|
||||
|
||||
/**
|
||||
* A client for the OpenAI API.
|
||||
* @extends ApiClient
|
||||
*/
|
||||
class OpenAIAPI extends ApiClient {
|
||||
/**
|
||||
* Creates a new OpenAIAPI instance.
|
||||
*/
|
||||
constructor() {
|
||||
super('integrations', { accountScoped: true });
|
||||
|
||||
/**
|
||||
* The conversation events supported by the API.
|
||||
* @type {string[]}
|
||||
*/
|
||||
this.conversation_events = [
|
||||
'summarize',
|
||||
'reply_suggestion',
|
||||
'label_suggestion',
|
||||
];
|
||||
|
||||
/**
|
||||
* The message events supported by the API.
|
||||
* @type {string[]}
|
||||
*/
|
||||
this.message_events = ['rephrase'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an event using the OpenAI API.
|
||||
* @param {Object} options - The options for the event.
|
||||
* @param {string} [options.type='rephrase'] - The type of event to process.
|
||||
* @param {string} [options.content] - The content of the event.
|
||||
* @param {string} [options.tone] - The tone of the event.
|
||||
* @param {string} [options.conversationId] - The ID of the conversation to process the event for.
|
||||
* @param {string} options.hookId - The ID of the hook to use for processing the event.
|
||||
* @returns {Promise} A promise that resolves with the result of the event processing.
|
||||
*/
|
||||
processEvent({ type = 'rephrase', content, tone, conversationId, hookId }) {
|
||||
/**
|
||||
* @type {ConversationMessageData}
|
||||
*/
|
||||
let data = {
|
||||
tone,
|
||||
content,
|
||||
};
|
||||
|
||||
if (type === 'reply_suggestion' || type === 'summarize') {
|
||||
if (this.conversation_events.includes(type)) {
|
||||
data = {
|
||||
conversation_display_id: conversationId,
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
border-radius: var(--border-radius-normal);
|
||||
box-shadow: none;
|
||||
display: flex;
|
||||
height: 4rem;
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.mx-input:disabled,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
select {
|
||||
height: 4.0rem;
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
@@ -20,15 +20,6 @@ select {
|
||||
margin-left: var(--space-normal);
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
background-color: var(--black-transparent);
|
||||
border-radius: $space-smaller;
|
||||
font-size: $font-size-mini;
|
||||
max-width: var(--space-giga);
|
||||
padding: $space-smaller $space-small;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
code {
|
||||
border: 0;
|
||||
font-family: 'ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas',
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
// Disable contrast warnings in Foundation.
|
||||
$contrast-warnings: false;
|
||||
|
||||
$global-font-size: 10px;
|
||||
$global-font-size: 16px;
|
||||
$global-width: 100%;
|
||||
$global-lineheight: 1.5;
|
||||
$foundation-palette: (primary: $color-woot,
|
||||
@@ -63,7 +63,7 @@ $black: #000;
|
||||
$white: #fff;
|
||||
$body-background: $white;
|
||||
$body-font-color: $color-body;
|
||||
$body-font-family: 'Inter',
|
||||
$body-font-family: 'PlusJakarta',
|
||||
-apple-system,
|
||||
system-ui,
|
||||
BlinkMacSystemFont,
|
||||
@@ -117,7 +117,7 @@ $header-font-style: normal;
|
||||
$font-family-monospace: $body-font-family;
|
||||
$header-color: $color-heading;
|
||||
$header-lineheight: 1.4;
|
||||
$header-margin-bottom: 0.5rem;
|
||||
$header-margin-bottom: 0.3125rem;
|
||||
$header-styles: (small: ("h1": ("font-size": 24),
|
||||
"h2": ("font-size": 20),
|
||||
"h3": ("font-size": 19),
|
||||
@@ -133,7 +133,7 @@ $header-styles: (small: ("h1": ("font-size": 24),
|
||||
$header-text-rendering: optimizeLegibility;
|
||||
$small-font-size: 80%;
|
||||
$header-small-font-color: $medium-gray;
|
||||
$paragraph-lineheight: 1.45;
|
||||
$paragraph-lineheight: 1.65;
|
||||
$paragraph-margin-bottom: var(--space-small);
|
||||
$paragraph-text-rendering: optimizeLegibility;
|
||||
$code-color: $black;
|
||||
@@ -153,11 +153,11 @@ $list-lineheight: $paragraph-lineheight;
|
||||
$list-margin-bottom: $paragraph-margin-bottom;
|
||||
$list-style-type: disc;
|
||||
$list-style-position: outside;
|
||||
$list-side-margin: 1.25rem;
|
||||
$list-nested-side-margin: 1.25rem;
|
||||
$defnlist-margin-bottom: 1rem;
|
||||
$list-side-margin: 0.78125rem;
|
||||
$list-nested-side-margin: 0.78125rem;
|
||||
$defnlist-margin-bottom: 0.6875rem;
|
||||
$defnlist-term-weight: $global-weight-bold;
|
||||
$defnlist-term-margin-bottom: 0.3rem;
|
||||
$defnlist-term-margin-bottom: 0.1875rem;
|
||||
$blockquote-color: $dark-gray;
|
||||
$blockquote-padding: rem-calc(9 20 0 19);
|
||||
$blockquote-border: 1px solid $medium-gray;
|
||||
@@ -179,9 +179,9 @@ $lead-lineheight: 1.6;
|
||||
$subheader-lineheight: 1.4;
|
||||
$subheader-color: $dark-gray;
|
||||
$subheader-font-weight: $global-weight-normal;
|
||||
$subheader-margin-top: 0.2rem;
|
||||
$subheader-margin-bottom: 0.5rem;
|
||||
$stat-font-size: 2.5rem;
|
||||
$subheader-margin-top: 0.125rem;
|
||||
$subheader-margin-bottom: 0.3125rem;
|
||||
$stat-font-size: 1.5625rem;
|
||||
|
||||
// 6. Abide
|
||||
// --------
|
||||
@@ -202,11 +202,11 @@ $accordion-plusminus: true;
|
||||
$accordion-title-font-size: rem-calc(12);
|
||||
$accordion-item-color: $primary-color;
|
||||
$accordion-item-background-hover: $light-gray;
|
||||
$accordion-item-padding: 1.25rem 1rem;
|
||||
$accordion-item-padding: 0.78125rem 0.625rem;
|
||||
$accordion-content-background: $white;
|
||||
$accordion-content-border: 1px solid $light-gray;
|
||||
$accordion-content-color: $body-font-color;
|
||||
$accordion-content-padding: 1rem;
|
||||
$accordion-content-padding: 0.625rem;
|
||||
|
||||
// 8. Accordion Menu
|
||||
// -----------------
|
||||
@@ -234,7 +234,7 @@ $breadcrumbs-item-font-size: rem-calc(11);
|
||||
$breadcrumbs-item-color: $primary-color;
|
||||
$breadcrumbs-item-color-current: $black;
|
||||
$breadcrumbs-item-color-disabled: $medium-gray;
|
||||
$breadcrumbs-item-margin: 0.75rem;
|
||||
$breadcrumbs-item-margin: 0.46875rem;
|
||||
$breadcrumbs-item-uppercase: true;
|
||||
$breadcrumbs-item-slash: true;
|
||||
|
||||
@@ -275,8 +275,8 @@ $buttongroup-radius-on-each: false;
|
||||
$callout-background: $white;
|
||||
$callout-background-fade: 85%;
|
||||
$callout-border: 1px solid rgba($black, 0.25);
|
||||
$callout-margin: 0 0 1rem 0;
|
||||
$callout-padding: 1rem;
|
||||
$callout-margin: 0 0 0.625rem 0;
|
||||
$callout-padding: 0.625rem;
|
||||
$callout-font-color: $body-font-color;
|
||||
$callout-font-color-alt: $body-background;
|
||||
$callout-radius: $global-radius;
|
||||
@@ -320,10 +320,10 @@ $drilldown-background: $white;
|
||||
// 17. Dropdown
|
||||
// ------------
|
||||
|
||||
$dropdown-padding: 1rem;
|
||||
$dropdown-padding: 0.625rem;
|
||||
$dropdown-background: $body-background;
|
||||
$dropdown-border: 1px solid $medium-gray;
|
||||
$dropdown-font-size: 1rem;
|
||||
$dropdown-font-size: 0.625rem;
|
||||
$dropdown-width: 300px;
|
||||
$dropdown-radius: $global-radius;
|
||||
$dropdown-sizes: (tiny: 100px,
|
||||
@@ -354,7 +354,7 @@ $helptext-font-style: italic;
|
||||
$input-prefix-color: $color-body;
|
||||
$input-prefix-background: var(--b-100);
|
||||
$input-prefix-border: 1px solid $color-border;
|
||||
$input-prefix-padding: 1rem;
|
||||
$input-prefix-padding: 0.625rem;
|
||||
$form-label-color: $color-body;
|
||||
$form-label-font-size: rem-calc(14);
|
||||
$form-label-font-weight: $font-weight-medium;
|
||||
@@ -406,14 +406,14 @@ $menu-margin-nested: $space-medium;
|
||||
$menu-item-padding: $space-slab;
|
||||
$menu-item-color-active: $white;
|
||||
$menu-item-background-active: $color-background;
|
||||
$menu-icon-spacing: 0.25rem;
|
||||
$menu-icon-spacing: 0.15625rem;
|
||||
$menu-item-background-hover: $light-gray;
|
||||
$menu-border: $light-gray;
|
||||
|
||||
// 23. Meter
|
||||
// ---------
|
||||
|
||||
$meter-height: 1rem;
|
||||
$meter-height: 0.625rem;
|
||||
$meter-radius: $global-radius;
|
||||
$meter-background: $medium-gray;
|
||||
$meter-fill-good: $success-color;
|
||||
@@ -423,11 +423,11 @@ $meter-fill-bad: $alert-color;
|
||||
// 24. Off-canvas
|
||||
// --------------
|
||||
|
||||
$offcanvas-sizes: (small: 23rem,
|
||||
medium: 23rem,
|
||||
$offcanvas-sizes: (small: 14.375,
|
||||
medium: 14.375,
|
||||
);
|
||||
$offcanvas-vertical-sizes: (small: 23rem,
|
||||
medium: 23rem,
|
||||
$offcanvas-vertical-sizes: (small: 14.375,
|
||||
medium: 14.375,
|
||||
);
|
||||
$offcanvas-background: $light-gray;
|
||||
$offcanvas-shadow: 0 0 10px rgba($black, 0.7);
|
||||
@@ -445,14 +445,14 @@ $maincontent-class: 'off-canvas-content';
|
||||
|
||||
$orbit-bullet-background: $medium-gray;
|
||||
$orbit-bullet-background-active: $dark-gray;
|
||||
$orbit-bullet-diameter: 1.2rem;
|
||||
$orbit-bullet-margin: 0.1rem;
|
||||
$orbit-bullet-margin-top: 0.8rem;
|
||||
$orbit-bullet-margin-bottom: 0.8rem;
|
||||
$orbit-bullet-diameter: 0.75rem;
|
||||
$orbit-bullet-margin: 0.0625rem;
|
||||
$orbit-bullet-margin-top: 0.5rem;
|
||||
$orbit-bullet-margin-bottom: 0.5rem;
|
||||
$orbit-caption-background: rgba($black, 0.5);
|
||||
$orbit-caption-padding: 1rem;
|
||||
$orbit-caption-padding: 0.625rem;
|
||||
$orbit-control-background-hover: rgba($black, 0.5);
|
||||
$orbit-control-padding: 1rem;
|
||||
$orbit-control-padding: 0.625rem;
|
||||
$orbit-control-zindex: 10;
|
||||
|
||||
// 26. Pagination
|
||||
@@ -476,7 +476,7 @@ $pagination-arrows: true;
|
||||
// 27. Progress Bar
|
||||
// ----------------
|
||||
|
||||
$progress-height: 1rem;
|
||||
$progress-height: 0.625rem;
|
||||
$progress-background: $medium-gray;
|
||||
$progress-margin-bottom: $global-margin;
|
||||
$progress-meter-background: $primary-color;
|
||||
@@ -504,13 +504,13 @@ $reveal-overlay-background: rgba($black, 0.45);
|
||||
// 30. Slider
|
||||
// ----------
|
||||
|
||||
$slider-width-vertical: 0.5rem;
|
||||
$slider-width-vertical: 0.3125rem;
|
||||
$slider-transition: all 0.2s ease-in-out;
|
||||
$slider-height: 0.5rem;
|
||||
$slider-height: 0.3125rem;
|
||||
$slider-background: $light-gray;
|
||||
$slider-fill-background: $medium-gray;
|
||||
$slider-handle-height: 1.4rem;
|
||||
$slider-handle-width: 1.4rem;
|
||||
$slider-handle-height: 0.875rem;
|
||||
$slider-handle-width: 0.875rem;
|
||||
$slider-handle-background: $primary-color;
|
||||
$slider-opacity-disabled: 0.25;
|
||||
$slider-radius: $global-radius;
|
||||
@@ -569,7 +569,7 @@ $tab-expand-max: 6;
|
||||
$tab-content-background: transparent;
|
||||
$tab-content-border: transparent;
|
||||
$tab-content-color: foreground($tab-background, $primary-color);
|
||||
$tab-content-padding: 1rem;
|
||||
$tab-content-padding: 0.625rem;
|
||||
|
||||
// 34. Thumbnail
|
||||
// -------------
|
||||
@@ -586,11 +586,11 @@ $thumbnail-radius: $global-radius;
|
||||
|
||||
$titlebar-background: $black;
|
||||
$titlebar-color: $white;
|
||||
$titlebar-padding: 0.5rem;
|
||||
$titlebar-padding: 0.3125rem;
|
||||
$titlebar-text-font-weight: bold;
|
||||
$titlebar-icon-color: $white;
|
||||
$titlebar-icon-color-hover: $medium-gray;
|
||||
$titlebar-icon-spacing: 0.25rem;
|
||||
$titlebar-icon-spacing: 0.15625rem;
|
||||
|
||||
// 36. Tooltip
|
||||
// -----------
|
||||
@@ -599,19 +599,19 @@ $has-tip-font-weight: $global-weight-bold;
|
||||
$has-tip-border-bottom: dotted 1px $dark-gray;
|
||||
$tooltip-background-color: $black;
|
||||
$tooltip-color: $white;
|
||||
$tooltip-padding: 0.75rem;
|
||||
$tooltip-padding: 0.46875rem;
|
||||
$tooltip-font-size: $font-size-mini;
|
||||
$tooltip-pip-width: 0.75rem;
|
||||
$tooltip-pip-width: 0.46875rem;
|
||||
$tooltip-pip-height: $tooltip-pip-width * 0.866;
|
||||
$tooltip-radius: $global-radius;
|
||||
|
||||
// 37. Top Bar
|
||||
// -----------
|
||||
|
||||
$topbar-padding: 0.5rem;
|
||||
$topbar-padding: 0.3125;
|
||||
$topbar-background: $light-gray;
|
||||
$topbar-submenu-background: $topbar-background;
|
||||
$topbar-title-spacing: 0.5rem 1rem 0.5rem 0;
|
||||
$topbar-title-spacing: 0.3125 0.625rem 0.3125 0;
|
||||
$topbar-input-width: 200px;
|
||||
$topbar-unstack-breakpoint: medium;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.bg-light {
|
||||
@include background-light;
|
||||
@apply bg-slate-25 dark:bg-slate-800;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
|
||||
@@ -22,43 +22,43 @@ $spinner-before-border-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
@mixin border-normal() {
|
||||
border: 1px solid $color-border;
|
||||
@apply border border-slate-50 dark:border-slate-700;
|
||||
}
|
||||
|
||||
@mixin border-normal-left() {
|
||||
border-left: 1px solid $color-border;
|
||||
@apply border-l border-slate-50 dark:border-slate-700;
|
||||
}
|
||||
|
||||
@mixin border-normal-top() {
|
||||
border-top: 1px solid $color-border;
|
||||
@apply border-t border-slate-50 dark:border-slate-700;
|
||||
}
|
||||
|
||||
@mixin border-normal-right() {
|
||||
border-right: 1px solid $color-border;
|
||||
@apply border-r border-slate-50 dark:border-slate-700;
|
||||
}
|
||||
|
||||
@mixin border-normal-bottom() {
|
||||
border-bottom: 1px solid $color-border;
|
||||
@apply border-b border-slate-50 dark:border-slate-700;
|
||||
}
|
||||
|
||||
@mixin border-light() {
|
||||
border: 1px solid $color-border-light;
|
||||
@apply border border-slate-25 dark:border-slate-700;
|
||||
}
|
||||
|
||||
@mixin border-light-left() {
|
||||
border-left: 1px solid $color-border-light;
|
||||
@apply border-l border-slate-25 dark:border-slate-700;
|
||||
}
|
||||
|
||||
@mixin border-light-top() {
|
||||
border-top: 1px solid $color-border-light;
|
||||
@apply border-t border-slate-25 dark:border-slate-700;
|
||||
}
|
||||
|
||||
@mixin border-light-right() {
|
||||
border-right: 1px solid $color-border-light;
|
||||
@apply border-r border-slate-25 dark:border-slate-700;
|
||||
}
|
||||
|
||||
@mixin border-light-bottom() {
|
||||
border-bottom: 1px solid $color-border-light;
|
||||
@apply border-b border-slate-25 dark:border-slate-700;
|
||||
}
|
||||
|
||||
// background
|
||||
@@ -67,11 +67,11 @@ $spinner-before-border-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
@mixin background-light() {
|
||||
background: $color-background-light;
|
||||
@apply bg-slate-50 dark:bg-slate-800;
|
||||
}
|
||||
|
||||
@mixin background-white() {
|
||||
background: $color-white;
|
||||
@apply bg-white dark:bg-slate-900;
|
||||
}
|
||||
|
||||
// input form
|
||||
@@ -237,8 +237,8 @@ $spinner-before-border-color: rgba(255, 255, 255, 0.7);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@mixin three-column-grid($column-one-width: 25.6rem,
|
||||
$column-three-width: 25.6rem) {
|
||||
@mixin three-column-grid($column-one-width: 16rem,
|
||||
$column-three-width: 16rem) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
|
||||
// Primary sidebar
|
||||
.primary--sidebar {
|
||||
border-left: 1px solid var(--s-50);
|
||||
border-right: 0;
|
||||
|
||||
.options-menu.dropdown-pane {
|
||||
right: var(--space-smaller);
|
||||
|
||||
@@ -20,63 +17,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Secondary sidebar
|
||||
.secondary-sidebar {
|
||||
.secondary-menu {
|
||||
border-left: 1px solid var(--s-50);
|
||||
border-right: 0;
|
||||
|
||||
.nested.vertical.menu {
|
||||
.badge--icon {
|
||||
margin-left: var(--space-smaller);
|
||||
margin-right: unset;
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.secondary-menu--icon {
|
||||
margin-left: var(--space-smaller);
|
||||
margin-right: unset;
|
||||
}
|
||||
|
||||
.account-context--group .account-context--switch-group {
|
||||
--overlay-shadow: linear-gradient(
|
||||
to left,
|
||||
rgba(255, 255, 255, 0) 0%,
|
||||
rgba(255, 255, 255, 1) 50%
|
||||
);
|
||||
background-image: var(--overlay-shadow);
|
||||
}
|
||||
|
||||
// Help center sidebar
|
||||
.sidebar-header--wrap .header-title--wrap {
|
||||
margin-left: unset;
|
||||
margin-right: var(--space-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Woot button
|
||||
.button {
|
||||
.icon--emoji + .button__content {
|
||||
padding-left: 0;
|
||||
padding-right: var(--space-small);
|
||||
}
|
||||
|
||||
.icon--font + .button__content {
|
||||
padding-left: 0;
|
||||
padding-right: var(--space-small);
|
||||
}
|
||||
|
||||
.icon + .button__content {
|
||||
padding-left: 0;
|
||||
padding-right: var(--space-small);
|
||||
}
|
||||
}
|
||||
|
||||
// Settings header
|
||||
.settings-header {
|
||||
.header--icon {
|
||||
@@ -439,7 +379,7 @@
|
||||
}
|
||||
|
||||
span {
|
||||
--minus-space-one-point-five: -1.5rem;
|
||||
--minus-space-one-point-five: -0.9375rem;
|
||||
|
||||
&.active {
|
||||
transform: translate(
|
||||
|
||||
@@ -29,4 +29,5 @@ a {
|
||||
|
||||
p {
|
||||
font-size: $font-size-small;
|
||||
word-spacing: .12em;
|
||||
}
|
||||
|
||||
@@ -43,17 +43,13 @@
|
||||
}
|
||||
|
||||
.border-right {
|
||||
border-right: 1px solid var(--color-border);
|
||||
@apply border-r border-slate-50 dark:border-slate-700;
|
||||
}
|
||||
|
||||
.border-left {
|
||||
border-left: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
background-color: var(--white);
|
||||
}
|
||||
|
||||
.text-ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
// Font sizes
|
||||
$font-size-nano: 0.8rem;
|
||||
$font-size-micro: 1.0rem;
|
||||
$font-size-mini: 1.2rem;
|
||||
$font-size-small: 1.4rem;
|
||||
$font-size-default: 1.6rem;
|
||||
$font-size-medium: 1.8rem;
|
||||
$font-size-large: 2.2rem;
|
||||
$font-size-big: 2.4rem;
|
||||
$font-size-bigger: 3.0rem;
|
||||
$font-size-mega: 3.4rem;
|
||||
$font-size-giga: 4.0rem;
|
||||
$font-size-nano: 0.5rem;
|
||||
$font-size-micro: 0.675rem;
|
||||
$font-size-mini: 0.75rem;
|
||||
$font-size-small: 0.875rem;
|
||||
$font-size-default: 1rem;
|
||||
$font-size-medium: 1.125rem;
|
||||
$font-size-large: 1.375rem;
|
||||
$font-size-big: 1.5rem;
|
||||
$font-size-bigger: 1.75rem;
|
||||
$font-size-mega: 2.125rem;
|
||||
$font-size-giga: 2.5rem;
|
||||
|
||||
// spaces
|
||||
$zero: 0;
|
||||
$space-micro: 0.2rem;
|
||||
$space-smaller: 0.4rem;
|
||||
$space-small: 0.8rem;
|
||||
$space-one: 1rem;
|
||||
$space-slab: 1.2rem;
|
||||
$space-normal: 1.6rem;
|
||||
$space-two: 2.0rem;
|
||||
$space-medium: 2.4rem;
|
||||
$space-large: 3.2rem;
|
||||
$space-larger: 4.8rem;
|
||||
$space-jumbo: 6.4rem;
|
||||
$space-mega: 10.0rem;
|
||||
$space-micro: 0.125rem;
|
||||
$space-smaller: 0.25rem;
|
||||
$space-small: 0.5rem;
|
||||
$space-one: 0.675rem;
|
||||
$space-slab: 0.75rem;
|
||||
$space-normal: 1rem;
|
||||
$space-two: 1.25rem;
|
||||
$space-medium: 1.5rem;
|
||||
$space-large: 2rem;
|
||||
$space-larger: 3rem;
|
||||
$space-jumbo: 4rem;
|
||||
$space-mega: 6.25rem;
|
||||
|
||||
// font-weight
|
||||
$font-weight-feather: 100;
|
||||
@@ -35,8 +35,8 @@ $font-weight-bold: 600;
|
||||
$font-weight-black: 700;
|
||||
|
||||
//Navbar
|
||||
$nav-bar-width: 23rem;
|
||||
$header-height: 5.6rem;
|
||||
$nav-bar-width: 14.375rem;
|
||||
$header-height: 3.5rem;
|
||||
|
||||
$woot-logo-padding: $space-large $space-two;
|
||||
|
||||
@@ -71,20 +71,20 @@ $color-primary-light: #c7e3ff;
|
||||
$color-primary-dark: darken($color-woot, 20%);
|
||||
|
||||
// Thumbnail
|
||||
$thumbnail-radius: 4rem;
|
||||
$thumbnail-radius: 2.5rem;
|
||||
|
||||
// chat-header
|
||||
$conv-header-height: 4rem;
|
||||
$conv-header-height: 2.5rem;
|
||||
|
||||
// Inbox List
|
||||
|
||||
$inbox-thumb-size: 4.8rem;
|
||||
$inbox-thumb-size: 3rem;
|
||||
|
||||
|
||||
// Spinner
|
||||
$spinkit-spinner-color: $color-white !default;
|
||||
$spinkit-spinner-margin: 0 0 0 1.6rem !default;
|
||||
$spinkit-size: 1.6rem !default;
|
||||
$spinkit-spinner-margin: 0 0 0 1rem !default;
|
||||
$spinkit-size: 1rem !default;
|
||||
|
||||
// Snackbar default
|
||||
$woot-snackbar-bg: #323232;
|
||||
@@ -101,5 +101,5 @@ $ionicons-font-path: '~ionicons/fonts';
|
||||
$transition-ease-in: all 0.250s ease-in;
|
||||
|
||||
:root {
|
||||
--dashboard-app-tabs-height: 3.9rem;
|
||||
--dashboard-app-tabs-height: 2.4375rem;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
@import 'shared/assets/fonts/inter';
|
||||
@import 'tailwindcss/base';
|
||||
@import 'tailwindcss/components';
|
||||
@import 'tailwindcss/utilities';
|
||||
|
||||
@import 'shared/assets/fonts/plus-jakarta';
|
||||
@import 'shared/assets/stylesheets/animations';
|
||||
@import 'shared/assets/stylesheets/colors';
|
||||
@import 'shared/assets/stylesheets/spacing';
|
||||
@@ -67,3 +71,8 @@
|
||||
@import 'plugins/dropdown';
|
||||
@import '~shared/assets/stylesheets/ionicons';
|
||||
@import 'utility-helpers';
|
||||
|
||||
|
||||
.tooltip {
|
||||
@apply bg-slate-900 text-white py-1 px-2 z-40 text-xs rounded-md dark:bg-slate-200 dark:text-slate-900;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
}
|
||||
|
||||
.multiselect__select {
|
||||
min-height: 4.6rem;
|
||||
min-height: 2.875rem;
|
||||
padding: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
@@ -98,7 +98,7 @@
|
||||
border: 1px solid var(--s-200);
|
||||
border-color: var(--s-200);
|
||||
margin: 0;
|
||||
min-height: 4.4rem;
|
||||
min-height: 2.75rem;
|
||||
padding-top: $zero;
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
.multiselect__input {
|
||||
@include ghost-input;
|
||||
font-size: $font-size-small;
|
||||
height: 4.4rem;
|
||||
height: 2.75rem;
|
||||
margin-bottom: $zero;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -168,7 +168,7 @@
|
||||
}
|
||||
|
||||
.multiselect-wrap--small {
|
||||
$multiselect-height: 4.0rem;
|
||||
$multiselect-height: 2.5rem;
|
||||
|
||||
.multiselect__tags,
|
||||
.multiselect__input {
|
||||
@@ -195,7 +195,7 @@
|
||||
display: flex;
|
||||
font-size: var(--font-size-small);
|
||||
margin: 0;
|
||||
max-height: 3.8rem;
|
||||
max-height: 2.375rem;
|
||||
padding: var(--space-smaller) var(--space-micro);
|
||||
}
|
||||
|
||||
@@ -219,7 +219,7 @@
|
||||
}
|
||||
|
||||
.multiselect-wrap--medium {
|
||||
$multiselect-height: 4.8rem;
|
||||
$multiselect-height: 3rem;
|
||||
|
||||
.multiselect__tags,
|
||||
.multiselect__input {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
@import 'shared/assets/fonts/inter';
|
||||
@import 'shared/assets/fonts/plus-jakarta';
|
||||
@import 'shared/assets/stylesheets/animations';
|
||||
@import 'shared/assets/stylesheets/colors';
|
||||
@import 'shared/assets/stylesheets/spacing';
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
@import 'shared/assets/fonts/inter';
|
||||
@import 'shared/assets/fonts/plus-jakarta';
|
||||
@import '../variables';
|
||||
@import '~shared/assets/stylesheets/ionicons';
|
||||
|
||||
@@ -4,10 +4,8 @@
|
||||
|
||||
// Conversation header - Light BG
|
||||
.settings-header {
|
||||
@include background-white;
|
||||
@include flex;
|
||||
@include flex-align($x: justify, $y: middle);
|
||||
border-bottom: 1px solid var(--s-50);
|
||||
height: $header-height;
|
||||
min-height: $header-height;
|
||||
padding: $space-small $space-normal;
|
||||
@@ -27,7 +25,7 @@
|
||||
|
||||
.wizard-box {
|
||||
.item {
|
||||
@include background-light;
|
||||
// @include background-light;
|
||||
|
||||
cursor: pointer;
|
||||
padding: $space-normal $space-normal $space-normal $space-medium;
|
||||
@@ -128,8 +126,8 @@
|
||||
}
|
||||
|
||||
.wizard-body {
|
||||
@include background-white;
|
||||
@include border-light;
|
||||
@include background-white;
|
||||
@include full-height();
|
||||
padding: $space-medium;
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
.integration--image {
|
||||
display: flex;
|
||||
height: 10rem;
|
||||
width: 10rem;
|
||||
height: 6.25rem;
|
||||
width: 6.25rem;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
|
||||
@@ -1,207 +1,201 @@
|
||||
$default-button-height: 4.0rem;
|
||||
|
||||
.button {
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
height: $default-button-height;
|
||||
margin-bottom: 0;
|
||||
@apply items-center inline-flex h-10 mb-0;
|
||||
|
||||
.button__content {
|
||||
width: 100%;
|
||||
@apply w-full;
|
||||
|
||||
img,
|
||||
svg {
|
||||
@apply inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
padding: 0 var(--space-small);
|
||||
@apply px-2 py-0;
|
||||
}
|
||||
|
||||
.icon--emoji+.button__content {
|
||||
padding-left: var(--space-small);
|
||||
.icon--emoji + .button__content {
|
||||
@apply pl-2 rtl:pr-2 rtl:pl-0;
|
||||
}
|
||||
|
||||
.icon--font+.button__content {
|
||||
padding-left: var(--space-small);
|
||||
.icon--font + .button__content {
|
||||
@apply pl-2 rtl:pr-2 rtl:pl-0;
|
||||
}
|
||||
|
||||
// @TODDO - Remove after moving all buttons to woot-button
|
||||
.icon+.button__content {
|
||||
padding-left: var(--space-small);
|
||||
width: auto;
|
||||
.icon + .button__content {
|
||||
@apply pl-2 w-auto rtl:pr-2 rtl:pl-0;
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@apply flex justify-center text-center;
|
||||
}
|
||||
|
||||
&.round {
|
||||
border-radius: $space-larger;
|
||||
@apply rounded-full;
|
||||
}
|
||||
|
||||
// @TODO Use with link
|
||||
|
||||
&.compact {
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
@apply pb-0 pt-0;
|
||||
}
|
||||
|
||||
&.hollow {
|
||||
border-color: var(--s-200);
|
||||
color: var(--w-700);
|
||||
@apply border border-slate-200 text-woot-700 dark:text-woot-100 hover:bg-woot-50 dark:hover:bg-woot-900;
|
||||
|
||||
&.secondary {
|
||||
border-color: var(--s-200);
|
||||
color: var(--s-700);
|
||||
@apply text-slate-700 dark:text-slate-100 hover:bg-slate-50 dark:hover:bg-slate-700;
|
||||
}
|
||||
|
||||
&.success {
|
||||
border-color: var(--s-200);
|
||||
color: var(--g-700);
|
||||
@apply text-green-700 dark:text-green-100 hover:bg-green-50 dark:hover:bg-green-800;
|
||||
}
|
||||
|
||||
&.alert {
|
||||
border-color: var(--s-200);
|
||||
color: var(--r-700);
|
||||
@apply text-red-700 dark:text-red-100 hover:bg-red-50 dark:hover:bg-red-800;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
border-color: var(--s-200);
|
||||
color: var(--y-700);
|
||||
@apply text-yellow-700 dark:text-yellow-100 hover:bg-yellow-50 dark:hover:bg-yellow-800;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--s-75);
|
||||
border-color: var(--s-100);
|
||||
@apply bg-slate-75 dark:bg-slate-900 border-slate-100 dark:border-slate-700;
|
||||
|
||||
&.secondary {
|
||||
border-color: var(--s-100);
|
||||
@apply border-slate-100 dark:border-slate-700;
|
||||
}
|
||||
|
||||
&.success {
|
||||
border-color: var(--s-100);
|
||||
@apply border-slate-100 dark:border-slate-700;
|
||||
}
|
||||
|
||||
&.alert {
|
||||
border-color: var(--s-100);
|
||||
@apply border-slate-100 dark:border-slate-700;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
border-color: var(--s-100);
|
||||
@apply border-slate-100 dark:border-slate-700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Smooth style
|
||||
&.smooth {
|
||||
@include button-style(var(--w-50), var(--w-100), var(--w-700));
|
||||
|
||||
@apply bg-woot-50 dark:bg-woot-800 text-woot-700 dark:text-woot-100 hover:text-woot-700 dark:hover:text-woot-700 hover:bg-woot-100 dark:hover:bg-woot-900;
|
||||
|
||||
&.secondary {
|
||||
@include button-style(var(--s-50), var(--s-100), var(--s-700));
|
||||
@apply bg-slate-50 dark:bg-slate-700 text-slate-700 dark:text-slate-100 hover:bg-slate-100 dark:hover:bg-slate-800;
|
||||
}
|
||||
|
||||
&.success {
|
||||
@include button-style(var(--g-50), var(--g-100), var(--g-700));
|
||||
@apply bg-green-50 dark:bg-green-700 text-green-700 dark:text-green-100 hover:bg-green-100 dark:hover:bg-green-800;
|
||||
}
|
||||
|
||||
&.alert {
|
||||
@include button-style(var(--r-50), var(--r-100), var(--r-700));
|
||||
@apply bg-red-50 dark:bg-red-700 dark:bg-opacity-50 text-red-700 dark:text-red-100 hover:bg-red-100 dark:hover:bg-red-800 dark:hover:bg-opacity-30;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
@include button-style(var(--y-100), var(--y-200), var(--y-700));
|
||||
@apply bg-yellow-100 dark:bg-yellow-100 text-yellow-700 dark:text-yellow-100 hover:bg-yellow-200 dark:hover:bg-yellow-200;
|
||||
}
|
||||
}
|
||||
|
||||
&.clear {
|
||||
color: var(--w-700);
|
||||
@apply text-woot-500 dark:text-woot-500;
|
||||
|
||||
&.secondary {
|
||||
color: var(--s-700);
|
||||
@apply text-slate-700 dark:text-slate-100;
|
||||
}
|
||||
|
||||
&.success {
|
||||
color: var(--g-700);
|
||||
@apply text-green-700 dark:text-green-100;
|
||||
}
|
||||
|
||||
&.alert {
|
||||
color: var(--r-700);
|
||||
@apply text-red-700 dark:text-red-100;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
color: var(--y-700);
|
||||
@apply text-yellow-700 dark:text-yellow-100;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--w-50);
|
||||
@apply hover:bg-woot-50 dark:hover:bg-woot-300;
|
||||
|
||||
&.secondary {
|
||||
background: var(--s-50);
|
||||
@apply hover:bg-slate-50 dark:hover:bg-slate-700;
|
||||
}
|
||||
|
||||
&.success {
|
||||
background: var(--g-50);
|
||||
@apply hover:bg-green-50 dark:hover:bg-green-800;
|
||||
}
|
||||
|
||||
&.alert {
|
||||
background: var(--r-50);
|
||||
@apply hover:bg-red-50 dark:hover:bg-red-800;
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background: var(--y-50);
|
||||
@apply hover:bg-yellow-50 dark:hover:bg-yellow-800;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
&.secondary {
|
||||
@apply active:bg-slate-100 dark:active:bg-slate-900;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
&.secondary {
|
||||
@apply focus:bg-slate-50 dark:focus:bg-slate-700;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sizes
|
||||
&.tiny {
|
||||
height: var(--space-medium);
|
||||
@apply h-6;
|
||||
|
||||
.icon+.button__content {
|
||||
padding-left: var(--space-micro);
|
||||
.icon + .button__content {
|
||||
@apply pl-1 rtl:pr-1 rtl:pl-0;
|
||||
}
|
||||
}
|
||||
|
||||
&.small {
|
||||
height: var(--space-large);
|
||||
padding-bottom: var(--space-smaller);
|
||||
padding-top: var(--space-smaller);
|
||||
@apply h-8 pb-1 pt-1;
|
||||
|
||||
.icon+.button__content {
|
||||
padding-left: var(--space-smaller);
|
||||
.icon + .button__content {
|
||||
@apply pl-1 rtl:pr-1 rtl:pl-0;
|
||||
}
|
||||
}
|
||||
|
||||
&.large {
|
||||
height: var(--space-larger);
|
||||
@apply h-12;
|
||||
}
|
||||
|
||||
&.button--only-icon {
|
||||
justify-content: center;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
width: $default-button-height;
|
||||
@apply justify-center pl-0 pr-0 w-10;
|
||||
|
||||
&.tiny {
|
||||
width: var(--space-medium);
|
||||
@apply w-6;
|
||||
}
|
||||
|
||||
&.small {
|
||||
width: var(--space-large);
|
||||
@apply w-8;
|
||||
}
|
||||
|
||||
&.large {
|
||||
width: var(--space-larger);
|
||||
@apply w-12;
|
||||
}
|
||||
}
|
||||
|
||||
&.link {
|
||||
height: auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@apply h-auto m-0 p-0;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
@apply underline;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
$resolve-button-width: 13.2rem;
|
||||
$resolve-button-width: 8.25rem;
|
||||
|
||||
// Conversation header - Light BG
|
||||
.conv-header {
|
||||
@@ -14,12 +14,12 @@ $resolve-button-width: 13.2rem;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--space-smaller);
|
||||
margin-right: var(--space-small);
|
||||
width: 21.6rem;
|
||||
width: 13.5rem;
|
||||
|
||||
.icon {
|
||||
color: $medium-gray;
|
||||
font-size: $font-size-default;
|
||||
line-height: 3.8rem;
|
||||
line-height: 2.375rem;
|
||||
padding-left: $space-slab;
|
||||
padding-right: $space-smaller;
|
||||
}
|
||||
@@ -59,11 +59,6 @@ $resolve-button-width: 13.2rem;
|
||||
flex-direction: row;
|
||||
flex-grow: 1;
|
||||
justify-content: flex-end;
|
||||
margin-top: var(--space-small);
|
||||
|
||||
@include breakpoint(medium up) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&.has-open-sidebar {
|
||||
justify-content: flex-end;
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
.conversation {
|
||||
@include flex;
|
||||
@include flex-shrink;
|
||||
border-bottom: 1px solid transparent;
|
||||
border-left: var(--space-micro) solid transparent;
|
||||
border-top: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
padding: 0 var(--space-normal);
|
||||
position: relative;
|
||||
@@ -22,35 +20,11 @@
|
||||
&.active {
|
||||
animation: left-shift-animation 0.25s $swift-ease-out-function;
|
||||
background: var(--color-background);
|
||||
border-bottom-color: var(--color-border-light);
|
||||
border-left-color: var(--color-woot);
|
||||
border-top-color: var(--color-border-light);
|
||||
|
||||
.conversation--details {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
|
||||
+ .conversation .conversation--details {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
.conversation--details {
|
||||
border-top-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
.conversation--details {
|
||||
border-bottom-color: var(--color-border-light);
|
||||
}
|
||||
}
|
||||
|
||||
.conversation--details {
|
||||
@include border-light-bottom;
|
||||
@include border-light-top;
|
||||
border-bottom-color: transparent;
|
||||
padding: var(--space-slab) 0;
|
||||
}
|
||||
|
||||
@@ -81,7 +55,12 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 27rem;
|
||||
width: 16.875rem;
|
||||
|
||||
img,
|
||||
svg {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.conversation--meta {
|
||||
|
||||
@@ -273,7 +273,7 @@
|
||||
}
|
||||
|
||||
.wrap {
|
||||
--bubble-max-width: 49.6rem;
|
||||
--bubble-max-width: 31rem;
|
||||
margin: $zero $space-normal;
|
||||
max-width: Min(var(--bubble-max-width), 84%);
|
||||
|
||||
@@ -390,3 +390,42 @@
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.conversation-sidebar-wrap {
|
||||
flex: 0 0;
|
||||
flex-basis: 100%;
|
||||
height: auto;
|
||||
overflow: auto;
|
||||
z-index: var(--z-index-low);
|
||||
|
||||
@include breakpoint(medium up) {
|
||||
flex-basis: 17.5rem;
|
||||
}
|
||||
|
||||
@include breakpoint(large up) {
|
||||
flex-basis: 18.75rem;
|
||||
}
|
||||
|
||||
@include breakpoint(xlarge up) {
|
||||
flex-basis: 19.375rem;
|
||||
}
|
||||
|
||||
@include breakpoint(xxlarge up) {
|
||||
flex-basis: 20.625rem;
|
||||
}
|
||||
|
||||
@include breakpoint(xxxlarge up) {
|
||||
flex-basis: 25rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.activity-wrap {
|
||||
.message-text--metadata {
|
||||
.time {
|
||||
@include breakpoint(xlarge up) {
|
||||
margin-left: var(--space-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,3 +61,7 @@ input {
|
||||
border-color: var(--r-400);
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
@apply dark:text-slate-300;
|
||||
}
|
||||
|
||||
@@ -27,23 +27,22 @@
|
||||
padding: $space-large $space-large $zero;
|
||||
|
||||
img {
|
||||
max-height: 6rem;
|
||||
max-height: 3.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-container {
|
||||
@include normal-shadow;
|
||||
|
||||
background-color: $color-white;
|
||||
border-radius: $space-smaller;
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
width: 60rem;
|
||||
width: 37.5rem;
|
||||
|
||||
&.medium {
|
||||
max-width: 80%;
|
||||
width: 90rem;
|
||||
width: 56.25rem;
|
||||
}
|
||||
|
||||
.content-box {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.reply-box {
|
||||
transition: box-shadow 0.35s $swift-ease-out-function,
|
||||
height 2s $swift-ease-out-function;
|
||||
height 2s $swift-ease-out-function;
|
||||
|
||||
&.is-focused {
|
||||
box-shadow: var(--shadow);
|
||||
@@ -29,7 +29,7 @@
|
||||
// Override min-height : 50px in foundation
|
||||
//
|
||||
max-height: $space-mega * 2.4;
|
||||
min-height: 4.8rem;
|
||||
min-height: 3rem;
|
||||
padding: var(--space-normal) 0 0;
|
||||
resize: none;
|
||||
}
|
||||
@@ -40,7 +40,7 @@
|
||||
margin: 0;
|
||||
max-height: $space-mega * 2.4;
|
||||
// Override min-height : 50px in foundation
|
||||
min-height: 4.8rem;
|
||||
min-height: 3rem;
|
||||
padding: var(--space-normal) 0 0;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
|
||||
.dropdown-pane {
|
||||
bottom: 6rem;
|
||||
bottom: 3.75rem;
|
||||
display: block;
|
||||
visibility: visible;
|
||||
width: fit-content;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.ui-snackbar-container {
|
||||
left: 0;
|
||||
margin: 0 auto;
|
||||
max-width: 40rem;
|
||||
max-width: 25rem;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
@@ -16,9 +16,9 @@
|
||||
border-radius: $space-smaller;
|
||||
display: inline-flex;
|
||||
margin-bottom: $space-small;
|
||||
max-width: 40rem;
|
||||
min-height: 3rem;
|
||||
min-width: 24rem;
|
||||
max-width: 25rem;
|
||||
min-height: 1.875rem;
|
||||
min-width: 15rem;
|
||||
padding: $space-slab $space-medium;
|
||||
text-align: left;
|
||||
}
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
.ui-snackbar-action {
|
||||
margin-left: auto;
|
||||
padding-left: 3rem;
|
||||
padding-left: 1.875rem;
|
||||
|
||||
button {
|
||||
background: none;
|
||||
|
||||
@@ -1,18 +1,3 @@
|
||||
.loading-state {
|
||||
padding: $space-jumbo $space-smaller;
|
||||
|
||||
.message {
|
||||
color: $color-gray;
|
||||
display: block;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
float: none;
|
||||
top: -$space-smaller;
|
||||
}
|
||||
}
|
||||
|
||||
// EMPTY STATES
|
||||
.empty-state {
|
||||
|
||||
@@ -4,15 +4,13 @@ table {
|
||||
|
||||
thead {
|
||||
th {
|
||||
font-weight: var(--font-weight-bold);
|
||||
text-align: left;
|
||||
text-transform: uppercase;
|
||||
@apply font-medium text-left uppercase text-slate-900 dark:text-slate-200;
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
tr {
|
||||
border-bottom: 1px solid var(--color-border-light);
|
||||
@apply border-b border-slate-50 dark:border-slate-700;
|
||||
}
|
||||
|
||||
td {
|
||||
@@ -43,15 +41,15 @@ table {
|
||||
|
||||
.woot-thumbnail {
|
||||
border-radius: 50%;
|
||||
height: 5rem;
|
||||
width: 5rem;
|
||||
height: 3.125rem;
|
||||
width: 3.125rem;
|
||||
}
|
||||
|
||||
.button-wrapper {
|
||||
@include flex-align(left, null);
|
||||
@include flex;
|
||||
flex-direction: row;
|
||||
min-width: 20rem;
|
||||
min-width: 12.5rem;
|
||||
}
|
||||
|
||||
.button {
|
||||
|
||||
@@ -126,27 +126,28 @@
|
||||
class="conversations-list"
|
||||
:class="{ 'is-context-menu-open': isContextMenuOpen }"
|
||||
>
|
||||
<conversation-card
|
||||
v-for="chat in conversationList"
|
||||
:key="chat.id"
|
||||
:active-label="label"
|
||||
:team-id="teamId"
|
||||
:folders-id="foldersId"
|
||||
:chat="chat"
|
||||
:conversation-type="conversationType"
|
||||
:show-assignee="showAssigneeInConversationCard"
|
||||
:selected="isConversationSelected(chat.id)"
|
||||
@select-conversation="selectConversation"
|
||||
@de-select-conversation="deSelectConversation"
|
||||
@assign-agent="onAssignAgent"
|
||||
@assign-team="onAssignTeam"
|
||||
@assign-label="onAssignLabels"
|
||||
@update-conversation-status="toggleConversationStatus"
|
||||
@context-menu-toggle="onContextMenuToggle"
|
||||
@mark-as-unread="markAsUnread"
|
||||
@assign-priority="assignPriority"
|
||||
/>
|
||||
|
||||
<div>
|
||||
<conversation-card
|
||||
v-for="chat in conversationList"
|
||||
:key="chat.id"
|
||||
:active-label="label"
|
||||
:team-id="teamId"
|
||||
:folders-id="foldersId"
|
||||
:chat="chat"
|
||||
:conversation-type="conversationType"
|
||||
:show-assignee="showAssigneeInConversationCard"
|
||||
:selected="isConversationSelected(chat.id)"
|
||||
@select-conversation="selectConversation"
|
||||
@de-select-conversation="deSelectConversation"
|
||||
@assign-agent="onAssignAgent"
|
||||
@assign-team="onAssignTeam"
|
||||
@assign-label="onAssignLabels"
|
||||
@update-conversation-status="toggleConversationStatus"
|
||||
@context-menu-toggle="onContextMenuToggle"
|
||||
@mark-as-unread="markAsUnread"
|
||||
@assign-priority="assignPriority"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="chatListLoading" class="text-center">
|
||||
<span class="spinner" />
|
||||
</div>
|
||||
@@ -155,6 +156,7 @@
|
||||
v-if="!hasCurrentPageEndReached && !chatListLoading"
|
||||
variant="clear"
|
||||
size="expanded"
|
||||
class="text-center"
|
||||
@click="loadMoreConversations"
|
||||
>
|
||||
{{ $t('CHAT_LIST.LOAD_MORE_CONVERSATIONS') }}
|
||||
@@ -956,8 +958,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '~dashboard/assets/scss/woot';
|
||||
|
||||
.spinner {
|
||||
margin-top: var(--space-normal);
|
||||
margin-bottom: var(--space-normal);
|
||||
@@ -972,7 +972,7 @@ export default {
|
||||
|
||||
.conversations-list-wrap {
|
||||
flex-shrink: 0;
|
||||
flex-basis: clamp(32rem, 4vw + 34rem, 44rem);
|
||||
flex-basis: clamp(20rem, 4vw + 21.25rem, 27.5rem);
|
||||
overflow: hidden;
|
||||
|
||||
&.hide {
|
||||
|
||||
@@ -343,11 +343,11 @@ export default {
|
||||
.error-message {
|
||||
color: var(--r-400);
|
||||
display: block;
|
||||
font-size: 1.4rem;
|
||||
font-size: 0.875rem;
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: 400;
|
||||
margin-bottom: 1rem;
|
||||
margin-top: -1.6rem;
|
||||
margin-bottom: 0.625rem;
|
||||
margin-top: -1rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,8 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
modalContainerClassName() {
|
||||
let className = 'modal-container skip-context-menu';
|
||||
let className =
|
||||
'modal-container bg-white dark:bg-slate-800 skip-context-menu';
|
||||
if (this.fullWidth) {
|
||||
return `${className} modal-container--full-width`;
|
||||
}
|
||||
@@ -106,7 +107,7 @@ export default {
|
||||
.modal-container {
|
||||
border-radius: 0;
|
||||
height: 100%;
|
||||
width: 48rem;
|
||||
width: 30rem;
|
||||
}
|
||||
}
|
||||
.modal-big {
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
<template>
|
||||
<div class="column page-top-bar">
|
||||
<img v-if="headerImage" :src="headerImage" alt="No image" />
|
||||
<h2 class="page-sub-title">
|
||||
<h2
|
||||
ref="modalHeaderTitle"
|
||||
class="text-slate-800 text-lg dark:text-slate-100"
|
||||
>
|
||||
{{ headerTitle }}
|
||||
</h2>
|
||||
<p v-if="headerContent" class="small-12 column wrap-content">
|
||||
<p
|
||||
v-if="headerContent"
|
||||
ref="modalHeaderContent"
|
||||
class="small-12 column wrap-content"
|
||||
>
|
||||
{{ headerContent }}
|
||||
<span v-if="headerContentValue" class="content-value">
|
||||
{{ headerContentValue }}
|
||||
|
||||
@@ -77,7 +77,7 @@ export default {
|
||||
@import '~dashboard/assets/scss/mixins';
|
||||
|
||||
.ui-notification-container {
|
||||
max-width: 40rem;
|
||||
max-width: 25rem;
|
||||
position: absolute;
|
||||
right: var(--space-normal);
|
||||
top: var(--space-normal);
|
||||
@@ -94,7 +94,7 @@ export default {
|
||||
border-radius: var(--border-radius-medium);
|
||||
box-shadow: var(--shadow-large);
|
||||
|
||||
min-width: 24rem;
|
||||
min-width: 15rem;
|
||||
padding: var(--space-normal);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<div class="row settings--section">
|
||||
<div class="row settings--section" :class="{ 'border-bottom': showBorder }">
|
||||
<div class="medium-4 small-12 title--section">
|
||||
<p class="sub-block-title">
|
||||
<p v-if="title" class="sub-block-title">
|
||||
{{ title }}
|
||||
</p>
|
||||
<p class="sub-head">
|
||||
<slot name="subTitle">
|
||||
<slot v-if="subTitle" name="subTitle">
|
||||
{{ subTitle }}
|
||||
</slot>
|
||||
</p>
|
||||
@@ -25,11 +25,15 @@ export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
subTitle: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
showBorder: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
note: {
|
||||
type: String,
|
||||
@@ -43,9 +47,13 @@ export default {
|
||||
@import '~dashboard/assets/scss/variables';
|
||||
|
||||
.settings--section {
|
||||
border-bottom: 1px solid $color-border;
|
||||
display: flex;
|
||||
padding: $space-normal $space-normal $space-normal 0;
|
||||
padding: 0 $space-normal $space-normal 0;
|
||||
|
||||
&.border-bottom {
|
||||
padding-top: $space-normal;
|
||||
border-bottom: 1px solid $color-border;
|
||||
}
|
||||
|
||||
.sub-block-title {
|
||||
color: $color-woot;
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
size="small"
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
class="-ml-3 text-black-900 dark:text-slate-300"
|
||||
icon="list"
|
||||
class="toggle-sidebar"
|
||||
@click="onMenuItemClick"
|
||||
/>
|
||||
</template>
|
||||
@@ -20,8 +20,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.toggle-sidebar {
|
||||
margin-left: var(--space-minus-small);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<kbd class="hotkey">
|
||||
<slot />
|
||||
</kbd>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
kbd.hotkey {
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
user-select: none;
|
||||
justify-content: center;
|
||||
padding: var(--space-micro);
|
||||
min-width: var(--space-normal);
|
||||
font-size: var(--font-size-micro);
|
||||
border-radius: var(--space-smaller);
|
||||
background-color: var(--color-background);
|
||||
border: 1px solid var(--color-border);
|
||||
text-transform: uppercase;
|
||||
color: var(--color-body);
|
||||
letter-spacing: var(--space-micro);
|
||||
line-height: var(--font-size-micro);
|
||||
}
|
||||
</style>
|
||||
@@ -50,15 +50,6 @@
|
||||
>
|
||||
<woot-dropdown-menu>
|
||||
<woot-dropdown-item v-if="!isPending">
|
||||
<woot-button
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
size="small"
|
||||
icon="book-clock"
|
||||
@click="() => toggleStatus(STATUS_TYPE.PENDING)"
|
||||
>
|
||||
{{ this.$t('CONVERSATION.RESOLVE_DROPDOWN.MARK_PENDING') }}
|
||||
</woot-button>
|
||||
<woot-button
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
@@ -69,6 +60,17 @@
|
||||
{{ this.$t('CONVERSATION.RESOLVE_DROPDOWN.SNOOZE_UNTIL') }}
|
||||
</woot-button>
|
||||
</woot-dropdown-item>
|
||||
<woot-dropdown-item v-if="!isPending">
|
||||
<woot-button
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
size="small"
|
||||
icon="book-clock"
|
||||
@click="() => toggleStatus(STATUS_TYPE.PENDING)"
|
||||
>
|
||||
{{ this.$t('CONVERSATION.RESOLVE_DROPDOWN.MARK_PENDING') }}
|
||||
</woot-button>
|
||||
</woot-dropdown-item>
|
||||
</woot-dropdown-menu>
|
||||
</div>
|
||||
<woot-modal
|
||||
@@ -258,11 +260,11 @@ export default {
|
||||
|
||||
.dropdown-pane {
|
||||
left: unset;
|
||||
top: 4.2rem;
|
||||
top: 2.625rem;
|
||||
margin-top: var(--space-micro);
|
||||
right: 0;
|
||||
max-width: 20rem;
|
||||
min-width: 15.6rem;
|
||||
max-width: 12.5rem;
|
||||
min-width: 9.75rem;
|
||||
|
||||
.dropdown-menu__item {
|
||||
margin-bottom: 0;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<woot-dropdown-item
|
||||
v-for="status in availabilityStatuses"
|
||||
:key="status.value"
|
||||
class="status-items"
|
||||
class="flex items-baseline"
|
||||
>
|
||||
<woot-button
|
||||
size="small"
|
||||
@@ -18,23 +18,25 @@
|
||||
</woot-button>
|
||||
</woot-dropdown-item>
|
||||
<woot-dropdown-divider />
|
||||
<woot-dropdown-item class="auto-offline--toggle">
|
||||
<div class="info-wrap">
|
||||
<woot-dropdown-item class="m-0 flex items-center justify-between p-2">
|
||||
<div class="flex items-center">
|
||||
<fluent-icon
|
||||
v-tooltip.right-start="$t('SIDEBAR.SET_AUTO_OFFLINE.INFO_TEXT')"
|
||||
icon="info"
|
||||
size="14"
|
||||
class="info-icon"
|
||||
class="mt-px"
|
||||
/>
|
||||
|
||||
<span class="auto-offline--text">
|
||||
<span
|
||||
class="my-0 mx-1 text-xs font-medium text-slate-600 dark:text-slate-100"
|
||||
>
|
||||
{{ $t('SIDEBAR.SET_AUTO_OFFLINE.TEXT') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<woot-switch
|
||||
size="small"
|
||||
class="auto-offline--switch"
|
||||
class="mt-px mx-1 mb-0"
|
||||
:value="currentUserAutoOffline"
|
||||
@input="updateAutoOffline"
|
||||
/>
|
||||
@@ -138,71 +140,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~dashboard/assets/scss/variables';
|
||||
|
||||
.status {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--space-micro) var(--space-smaller);
|
||||
}
|
||||
|
||||
.status-view {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
& &--title {
|
||||
color: var(--b-600);
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: var(--font-weight-medium);
|
||||
margin-left: var(--space-small);
|
||||
|
||||
&:first-letter {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-change {
|
||||
.dropdown-pane {
|
||||
top: -132px;
|
||||
right: var(--space-normal);
|
||||
}
|
||||
|
||||
.status-items {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
}
|
||||
|
||||
.auto-offline--toggle {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: var(--space-smaller);
|
||||
margin: 0;
|
||||
|
||||
.info-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.auto-offline--switch {
|
||||
margin: -1px var(--space-micro) 0;
|
||||
}
|
||||
|
||||
.auto-offline--text {
|
||||
margin: 0 var(--space-smaller);
|
||||
font-size: var(--font-size-mini);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--s-700);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<aside class="woot-sidebar">
|
||||
<aside class="h-full flex">
|
||||
<primary-sidebar
|
||||
:logo-source="globalConfig.logoThumbnail"
|
||||
:installation-name="globalConfig.installationName"
|
||||
@@ -11,22 +11,21 @@
|
||||
@key-shortcut-modal="toggleKeyShortcutModal"
|
||||
@open-notification-panel="openNotificationPanel"
|
||||
/>
|
||||
<div class="secondary-sidebar">
|
||||
<secondary-sidebar
|
||||
v-if="showSecondarySidebar"
|
||||
:class="sidebarClassName"
|
||||
:account-id="accountId"
|
||||
:inboxes="inboxes"
|
||||
:labels="labels"
|
||||
:teams="teams"
|
||||
:custom-views="customViews"
|
||||
:menu-config="activeSecondaryMenu"
|
||||
:current-role="currentRole"
|
||||
:is-on-chatwoot-cloud="isOnChatwootCloud"
|
||||
@add-label="showAddLabelPopup"
|
||||
@toggle-accounts="toggleAccountModal"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<secondary-sidebar
|
||||
v-if="showSecondarySidebar"
|
||||
:class="sidebarClassName"
|
||||
:account-id="accountId"
|
||||
:inboxes="inboxes"
|
||||
:labels="labels"
|
||||
:teams="teams"
|
||||
:custom-views="customViews"
|
||||
:menu-config="activeSecondaryMenu"
|
||||
:current-role="currentRole"
|
||||
:is-on-chatwoot-cloud="isOnChatwootCloud"
|
||||
@add-label="showAddLabelPopup"
|
||||
@toggle-accounts="toggleAccountModal"
|
||||
/>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
@@ -214,87 +213,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.woot-sidebar {
|
||||
background: var(--white);
|
||||
display: flex;
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
width: fit-content;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~dashboard/assets/scss/variables';
|
||||
|
||||
.account-selector--modal {
|
||||
.modal-container {
|
||||
width: 40rem;
|
||||
}
|
||||
}
|
||||
|
||||
.secondary-sidebar {
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.account-selector {
|
||||
cursor: pointer;
|
||||
padding: $space-small $space-large;
|
||||
|
||||
.selected--account {
|
||||
margin-top: -$space-smaller;
|
||||
|
||||
& + .account--details {
|
||||
padding-left: $space-normal - $space-micro;
|
||||
}
|
||||
}
|
||||
|
||||
.account--details {
|
||||
padding-left: $space-large + $space-smaller;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: $space-large;
|
||||
}
|
||||
|
||||
a {
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
|
||||
.account--name {
|
||||
cursor: pointer;
|
||||
font-size: $font-size-medium;
|
||||
font-weight: $font-weight-medium;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.account--role {
|
||||
cursor: pointer;
|
||||
font-size: $font-size-mini;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.app-context-menu {
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 6rem;
|
||||
}
|
||||
|
||||
.current-user--options {
|
||||
font-size: $font-size-big;
|
||||
margin-bottom: auto;
|
||||
margin-left: auto;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.secondary-menu .nested.vertical.menu {
|
||||
margin-left: var(--space-small);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,25 +1,29 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="showShowCurrentAccountContext"
|
||||
class="account-context--group"
|
||||
class="rounded-md text-xs py-2 px-2 mt-2 relative border border-slate-50 dark:border-slate-700 hover:bg-slate-50 dark:hover:bg-slate-700 cursor-pointer"
|
||||
@mouseover="setShowSwitch"
|
||||
@mouseleave="resetShowSwitch"
|
||||
>
|
||||
{{ $t('SIDEBAR.CURRENTLY_VIEWING_ACCOUNT') }}
|
||||
<p class="account-context--name text-ellipsis">
|
||||
<p class="text-ellipsis font-medium mb-0">
|
||||
{{ account.name }}
|
||||
</p>
|
||||
<transition name="fade">
|
||||
<div v-if="showSwitchButton" class="account-context--switch-group">
|
||||
<woot-button
|
||||
variant="clear"
|
||||
size="tiny"
|
||||
icon="arrow-swap"
|
||||
class="switch-button"
|
||||
@click="$emit('toggle-accounts')"
|
||||
>
|
||||
{{ $t('SIDEBAR.SWITCH') }}
|
||||
</woot-button>
|
||||
<div
|
||||
v-if="showSwitchButton"
|
||||
class="bg-gradient-to-r rtl:bg-gradient-to-l from-transparent via-white dark:via-slate-700 to-white dark:to-slate-700 flex items-center h-full justify-end absolute top-0 right-0 w-full"
|
||||
>
|
||||
<div class="my-0 mx-2">
|
||||
<woot-button
|
||||
variant="clear"
|
||||
size="tiny"
|
||||
icon="arrow-swap"
|
||||
@click="$emit('toggle-accounts')"
|
||||
>
|
||||
{{ $t('SIDEBAR.SWITCH') }}
|
||||
</woot-button>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
@@ -51,51 +55,6 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.account-context--group {
|
||||
border-radius: var(--border-radius-normal);
|
||||
border: 1px solid var(--color-border);
|
||||
font-size: var(--font-size-mini);
|
||||
padding: var(--space-small);
|
||||
margin: var(--space-small) var(--space-small) 0 var(--space-small);
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
background: var(--b-100);
|
||||
}
|
||||
|
||||
.account-context--name {
|
||||
font-weight: var(--font-weight-medium);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.switch-button {
|
||||
margin: 0 var(--space-small);
|
||||
}
|
||||
|
||||
.account-context--switch-group {
|
||||
--overlay-shadow: linear-gradient(
|
||||
to right,
|
||||
rgba(255, 255, 255, 0) 0%,
|
||||
rgba(255, 255, 255, 1) 50%
|
||||
);
|
||||
|
||||
align-items: center;
|
||||
background-image: var(--overlay-shadow);
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: var(--border-radius-normal);
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: var(--border-radius-normal);
|
||||
display: flex;
|
||||
height: 100%;
|
||||
justify-content: flex-end;
|
||||
opacity: 1;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 300ms ease;
|
||||
|
||||
@@ -2,31 +2,39 @@
|
||||
<woot-modal
|
||||
:show="showAccountModal"
|
||||
:on-close="() => $emit('close-account-modal')"
|
||||
class="account-selector--modal"
|
||||
>
|
||||
<woot-modal-header
|
||||
:header-title="$t('SIDEBAR_ITEMS.CHANGE_ACCOUNTS')"
|
||||
:header-content="$t('SIDEBAR_ITEMS.SELECTOR_SUBTITLE')"
|
||||
/>
|
||||
<div class="account-selector--wrap">
|
||||
<div class="px-8 pt-4 pb-8">
|
||||
<div
|
||||
v-for="account in currentUser.accounts"
|
||||
:id="`account-${account.id}`"
|
||||
:key="account.id"
|
||||
class="account-selector"
|
||||
class="pt-0 pb-0"
|
||||
>
|
||||
<button
|
||||
class="button expanded clear link"
|
||||
class="flex justify-between items-center expanded clear link cursor-pointer px-4 py-3 w-full rounded-lg hover:underline hover:bg-slate-25 dark:hover:bg-slate-900"
|
||||
@click="onChangeAccount(account.id)"
|
||||
>
|
||||
<span class="button__content">
|
||||
<label :for="account.name" class="account-details--wrap">
|
||||
<div class="account--name">{{ account.name }}</div>
|
||||
<div class="account--role">{{ account.role }}</div>
|
||||
<span class="w-full">
|
||||
<label :for="account.name" class="text-left rtl:text-right">
|
||||
<div
|
||||
class="text-slate-700 text-lg dark:text-slate-100 font-medium hover:underline-offset-4 leading-5"
|
||||
>
|
||||
{{ account.name }}
|
||||
</div>
|
||||
<div
|
||||
class="text-slate-500 text-xs dark:text-slate-500 font-medium hover:underline-offset-4"
|
||||
>
|
||||
{{ account.role }}
|
||||
</div>
|
||||
</label>
|
||||
</span>
|
||||
<fluent-icon
|
||||
v-show="account.id === accountId"
|
||||
class="selected--account"
|
||||
class="text-slate-800 dark:text-slate-100"
|
||||
icon="checkmark-circle"
|
||||
type="solid"
|
||||
size="24"
|
||||
@@ -74,32 +82,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.account-selector--wrap {
|
||||
margin-top: var(--space-normal);
|
||||
}
|
||||
.account-selector {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
.button {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: var(--space-one) var(--space-normal);
|
||||
.account-details--wrap {
|
||||
text-align: left;
|
||||
.account--name {
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-medium);
|
||||
font-weight: var(--font-weight-medium);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.account--role {
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-mini);
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="logo">
|
||||
<div class="w-8 h-8">
|
||||
<router-link :to="dashboardPath" replace>
|
||||
<img :src="source" :alt="name" />
|
||||
</router-link>
|
||||
@@ -30,17 +30,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
$logo-size: 32px;
|
||||
|
||||
.logo {
|
||||
padding: var(--space-normal);
|
||||
|
||||
img {
|
||||
width: $logo-size;
|
||||
height: $logo-size;
|
||||
object-fit: cover;
|
||||
object-position: left center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
<template>
|
||||
<div class="notifications-link">
|
||||
<woot-button
|
||||
class-names="notifications-link--button"
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
:class="{ 'is-active': isNotificationPanelActive }"
|
||||
<div class="mb-4">
|
||||
<button
|
||||
class="text-slate-600 dark:text-slate-100 w-10 h-10 my-2 flex items-center justify-center rounded-lg hover:bg-slate-25 dark:hover:bg-slate-800 dark:hover:text-slate-100 hover:text-slate-600 relative"
|
||||
:class="{
|
||||
'bg-woot-50 dark:bg-slate-800 text-woot-500 hover:bg-woot-50': isNotificationPanelActive,
|
||||
}"
|
||||
@click="openNotificationPanel"
|
||||
>
|
||||
<fluent-icon icon="alert" />
|
||||
<span v-if="unreadCount" class="badge warning">{{ unreadCount }}</span>
|
||||
</woot-button>
|
||||
<fluent-icon
|
||||
icon="alert"
|
||||
:class="{
|
||||
'text-woot-500': isNotificationPanelActive,
|
||||
}"
|
||||
/>
|
||||
<span
|
||||
v-if="unreadCount"
|
||||
class="text-black-900 bg-yellow-300 absolute -top-0.5 -right-1 p-1 text-xxs min-w-[1rem] rounded-full"
|
||||
>
|
||||
{{ unreadCount }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -43,37 +53,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.notifications-link {
|
||||
margin-bottom: var(--space-small);
|
||||
}
|
||||
|
||||
.badge {
|
||||
position: absolute;
|
||||
right: var(--space-minus-smaller);
|
||||
top: var(--space-minus-smaller);
|
||||
}
|
||||
.notifications-link--button {
|
||||
display: flex;
|
||||
position: relative;
|
||||
border-radius: var(--border-radius-large);
|
||||
border: 1px solid transparent;
|
||||
color: var(--s-600);
|
||||
margin: var(--space-small) 0;
|
||||
|
||||
&:hover {
|
||||
background: var(--w-50);
|
||||
color: var(--s-600);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: var(--w-500);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background: var(--w-50);
|
||||
color: var(--w-500);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,11 +3,10 @@
|
||||
<div
|
||||
v-if="show"
|
||||
v-on-clickaway="onClickAway"
|
||||
class="options-menu dropdown-pane"
|
||||
:class="{ 'dropdown-pane--open': show }"
|
||||
class="left-3 rtl:left-auto rtl:right-3 bottom-16 w-64 absolute z-10 rounded-md shadow-xl bg-white dark:bg-slate-800 py-2 px-2 border border-slate-25 dark:border-slate-700"
|
||||
:class="{ 'block visible': show }"
|
||||
>
|
||||
<availability-status />
|
||||
<li class="divider" />
|
||||
<woot-dropdown-menu>
|
||||
<woot-dropdown-item v-if="showChangeAccountOption">
|
||||
<woot-button
|
||||
@@ -50,7 +49,7 @@
|
||||
>
|
||||
<a
|
||||
:href="href"
|
||||
class="button small clear secondary"
|
||||
class="button small clear secondary bg-white dark:bg-slate-800 h-8"
|
||||
:class="{ 'is-active': isActive }"
|
||||
@click="e => handleProfileSettingClick(e, navigate)"
|
||||
>
|
||||
@@ -64,7 +63,7 @@
|
||||
<woot-dropdown-item v-if="currentUser.type === 'SuperAdmin'">
|
||||
<a
|
||||
href="/super_admin"
|
||||
class="button small clear secondary"
|
||||
class="button small clear secondary bg-white dark:bg-slate-800 h-8"
|
||||
target="_blank"
|
||||
rel="noopener nofollow noreferrer"
|
||||
@click="$emit('close')"
|
||||
@@ -149,12 +148,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.options-menu.dropdown-pane {
|
||||
left: var(--space-slab);
|
||||
bottom: var(--space-larger);
|
||||
min-width: var(--space-giga);
|
||||
top: unset;
|
||||
z-index: var(--z-index-low);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<template>
|
||||
<div class="primary--sidebar">
|
||||
<logo
|
||||
:source="logoSource"
|
||||
:name="installationName"
|
||||
:account-id="accountId"
|
||||
/>
|
||||
<nav class="menu vertical">
|
||||
<div
|
||||
class="h-full w-16 bg-white dark:bg-slate-900 border-r border-slate-50 dark:border-slate-700 rtl:border-l rtl:border-r-0 flex justify-between flex-col"
|
||||
>
|
||||
<div class="flex flex-col items-center">
|
||||
<logo
|
||||
:source="logoSource"
|
||||
:name="installationName"
|
||||
:account-id="accountId"
|
||||
class="m-4 mb-10"
|
||||
/>
|
||||
<primary-nav-item
|
||||
v-for="menuItem in menuItems"
|
||||
:key="menuItem.toState"
|
||||
@@ -14,8 +17,8 @@
|
||||
:to="menuItem.toState"
|
||||
:is-child-menu-active="menuItem.key === activeMenuItem"
|
||||
/>
|
||||
</nav>
|
||||
<div class="menu vertical user-menu">
|
||||
</div>
|
||||
<div class="flex flex-col items-center justify-end pb-6">
|
||||
<primary-nav-item
|
||||
v-if="!isACustomBrandedInstance"
|
||||
icon="book-open-globe"
|
||||
@@ -101,27 +104,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.primary--sidebar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: var(--space-jumbo);
|
||||
border-right: 1px solid var(--s-50);
|
||||
box-sizing: content-box;
|
||||
height: 100%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.menu {
|
||||
align-items: center;
|
||||
margin-top: var(--space-medium);
|
||||
}
|
||||
|
||||
.user-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: var(--space-normal);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,15 +3,28 @@
|
||||
<a
|
||||
v-tooltip.right="$t(`SIDEBAR.${name}`)"
|
||||
:href="href"
|
||||
class="button clear button--only-icon menu-item"
|
||||
:class="{ 'is-active': isActive || isChildMenuActive }"
|
||||
class="text-slate-600 dark:text-slate-100 w-10 h-10 my-2 flex items-center justify-center rounded-lg hover:bg-slate-25 dark:hover:bg-slate-800 dark:hover:text-slate-100 hover:text-slate-600 relative"
|
||||
:class="{
|
||||
'bg-woot-50 dark:bg-slate-800 text-woot-500 hover:bg-woot-50':
|
||||
isActive || isChildMenuActive,
|
||||
}"
|
||||
:rel="openInNewPage ? 'noopener noreferrer nofollow' : undefined"
|
||||
:target="openInNewPage ? '_blank' : undefined"
|
||||
@click="navigate"
|
||||
>
|
||||
<fluent-icon :icon="icon" />
|
||||
<span class="show-for-sr">{{ name }}</span>
|
||||
<span v-if="count" class="badge warning">{{ count }}</span>
|
||||
<fluent-icon
|
||||
:icon="icon"
|
||||
:class="{
|
||||
'text-woot-500': isActive || isChildMenuActive,
|
||||
}"
|
||||
/>
|
||||
<span class="sr-only">{{ name }}</span>
|
||||
<span
|
||||
v-if="count"
|
||||
class="text-black-900 bg-yellow-500 absolute -top-1 -right-1"
|
||||
>
|
||||
{{ count }}
|
||||
</span>
|
||||
</a>
|
||||
</router-link>
|
||||
</template>
|
||||
@@ -45,40 +58,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.button {
|
||||
margin: var(--space-small) 0;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
border-radius: var(--border-radius-large);
|
||||
border: 1px solid transparent;
|
||||
color: var(--s-600);
|
||||
|
||||
&:hover {
|
||||
background: var(--w-25);
|
||||
color: var(--s-600);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: var(--w-500);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background: var(--w-50);
|
||||
color: var(--w-500);
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: var(--font-size-default);
|
||||
}
|
||||
|
||||
.badge {
|
||||
position: absolute;
|
||||
right: var(--space-minus-smaller);
|
||||
top: var(--space-minus-smaller);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
<template>
|
||||
<div v-if="hasSecondaryMenu" class="main-nav secondary-menu">
|
||||
<div
|
||||
v-if="hasSecondaryMenu"
|
||||
class="h-full overflow-auto w-48 flex flex-col bg-white dark:bg-slate-900 border-r dark:border-slate-700 rtl:border-r-0 rtl:border-l border-slate-50 text-sm px-2 pb-8"
|
||||
>
|
||||
<account-context @toggle-accounts="toggleAccountModal" />
|
||||
<transition-group name="menu-list" tag="ul" class="menu vertical">
|
||||
<transition-group
|
||||
name="menu-list"
|
||||
tag="ul"
|
||||
class="pt-2 list-none ml-0 mb-0"
|
||||
>
|
||||
<secondary-nav-item
|
||||
v-for="menuItem in accessibleMenuItems"
|
||||
:key="menuItem.toState"
|
||||
@@ -249,27 +256,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import '~dashboard/assets/scss/woot';
|
||||
|
||||
.secondary-menu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--white);
|
||||
border-right: 1px solid var(--s-50);
|
||||
height: 100%;
|
||||
width: 20rem;
|
||||
flex-shrink: 0;
|
||||
overflow-y: hidden;
|
||||
position: unset;
|
||||
|
||||
&:hover {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.menu {
|
||||
padding: var(--space-small);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
+53
-110
@@ -5,38 +5,69 @@
|
||||
custom
|
||||
active-class="active"
|
||||
>
|
||||
<li :class="{ active: isActive }">
|
||||
<li
|
||||
class="font-medium h-7 my-1 hover:bg-slate-25 hover:text-bg-50 flex items-center px-2 rounded-md dark:hover:bg-slate-800"
|
||||
:class="{
|
||||
'bg-woot-25 dark:bg-slate-800': isActive,
|
||||
'text-ellipsis overflow-hidden whitespace-nowrap max-w-full': shouldTruncate,
|
||||
}"
|
||||
@click="navigate"
|
||||
>
|
||||
<a
|
||||
:href="href"
|
||||
class="button clear menu-item text-truncate"
|
||||
:class="{ 'is-active': isActive, 'text-truncate': shouldTruncate }"
|
||||
@click="navigate"
|
||||
class="inline-flex text-left max-w-full w-full items-center"
|
||||
>
|
||||
<span v-if="icon" class="badge--icon">
|
||||
<fluent-icon class="inbox-icon" :icon="icon" size="12" />
|
||||
<span
|
||||
v-if="icon"
|
||||
class="inline-flex items-center justify-center w-4 rounded-sm bg-slate-100 dark:bg-slate-700 p-0.5 mr-1.5 rtl:mr-0 rtl:ml-1.5"
|
||||
>
|
||||
<fluent-icon
|
||||
class="text-xxs text-slate-600 dark:text-slate-200"
|
||||
:class="{
|
||||
'text-woot-500 dark:text-woot-500': isActive,
|
||||
}"
|
||||
:icon="icon"
|
||||
size="12"
|
||||
/>
|
||||
</span>
|
||||
|
||||
<span
|
||||
v-if="labelColor"
|
||||
class="badge--label"
|
||||
class="inline-flex rounded-sm bg-slate-100 h-3 w-3.5 mr-1.5 rtl:mr-0 rtl:ml-1.5 border border-slate-50 dark:border-slate-900"
|
||||
:style="{ backgroundColor: labelColor }"
|
||||
/>
|
||||
<span
|
||||
:title="menuTitle"
|
||||
class="menu-label button__content"
|
||||
:class="{ 'text-truncate': shouldTruncate }"
|
||||
<div
|
||||
class="items-center flex overflow-hidden whitespace-nowrap text-ellipsis w-full justify-between"
|
||||
>
|
||||
{{ label }}
|
||||
<span v-if="showChildCount" class="count-view">
|
||||
<span
|
||||
:title="menuTitle"
|
||||
class="text-sm text-slate-600 dark:text-slate-100"
|
||||
:class="{
|
||||
'text-woot-500 dark:text-woot-500': isActive,
|
||||
'text-ellipsis overflow-hidden whitespace-nowrap max-w-full': shouldTruncate,
|
||||
}"
|
||||
>
|
||||
{{ label }}
|
||||
</span>
|
||||
<span
|
||||
v-if="showChildCount"
|
||||
class="bg-slate-50 dark:bg-slate-700 rounded text-xxs font-medium mx-1 py-0 px-1"
|
||||
:class="
|
||||
isCountZero
|
||||
? `text-slate-300 dark:text-slate-600`
|
||||
: `text-slate-600 dark:text-slate-50`
|
||||
"
|
||||
>
|
||||
{{ childItemCount }}
|
||||
</span>
|
||||
</span>
|
||||
<span v-if="count" class="badge" :class="{ secondary: !isActive }">
|
||||
{{ count }}
|
||||
</span>
|
||||
<span v-if="warningIcon" class="badge--icon">
|
||||
</div>
|
||||
<span
|
||||
v-if="warningIcon"
|
||||
class="inline-flex rounded-sm mr-1 bg-slate-100"
|
||||
>
|
||||
<fluent-icon
|
||||
v-tooltip.top-end="$t('SIDEBAR.FACEBOOK_REAUTHORIZE')"
|
||||
class="inbox-icon"
|
||||
class="text-xxs"
|
||||
:icon="warningIcon"
|
||||
size="12"
|
||||
/>
|
||||
@@ -72,10 +103,6 @@ export default {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
count: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
showChildCount: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@@ -89,96 +116,12 @@ export default {
|
||||
showIcon() {
|
||||
return { 'text-truncate': this.shouldTruncate };
|
||||
},
|
||||
isCountZero() {
|
||||
return this.childItemCount === 0;
|
||||
},
|
||||
menuTitle() {
|
||||
return this.shouldTruncate ? this.label : '';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
$badge-size: var(--space-normal);
|
||||
$label-badge-size: var(--space-slab);
|
||||
|
||||
.button {
|
||||
margin: var(--space-small) 0;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: inline-flex;
|
||||
color: var(--s-600);
|
||||
font-weight: var(--font-weight-medium);
|
||||
width: 100%;
|
||||
height: var(--space-medium);
|
||||
padding: var(--space-smaller) var(--space-smaller);
|
||||
margin: var(--space-smaller) 0;
|
||||
text-align: left;
|
||||
line-height: 1.2;
|
||||
|
||||
&:hover {
|
||||
background: var(--s-25);
|
||||
color: var(--s-600);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: var(--w-300);
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
background: var(--w-25);
|
||||
color: var(--w-500);
|
||||
border-color: var(--w-25);
|
||||
}
|
||||
&.is-active .count-view {
|
||||
background: var(--w-75);
|
||||
color: var(--w-500);
|
||||
}
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.inbox-icon {
|
||||
font-size: var(--font-size-nano);
|
||||
}
|
||||
|
||||
.badge--label,
|
||||
.badge--icon {
|
||||
display: inline-flex;
|
||||
border-radius: var(--border-radius-small);
|
||||
margin-right: var(--space-smaller);
|
||||
background: var(--s-100);
|
||||
}
|
||||
|
||||
.badge--icon {
|
||||
align-items: center;
|
||||
height: $badge-size;
|
||||
justify-content: center;
|
||||
min-width: $badge-size;
|
||||
}
|
||||
|
||||
.badge--label {
|
||||
height: $label-badge-size;
|
||||
min-width: $label-badge-size;
|
||||
margin-left: var(--space-smaller);
|
||||
border: 1px solid var(--color-border-light);
|
||||
}
|
||||
|
||||
.badge.secondary {
|
||||
min-width: unset;
|
||||
background: var(--s-75);
|
||||
color: var(--s-600);
|
||||
font-weight: var(--font-weight-bold);
|
||||
}
|
||||
|
||||
.count-view {
|
||||
background: var(--s-50);
|
||||
border-radius: var(--border-radius-normal);
|
||||
color: var(--s-600);
|
||||
font-size: var(--font-size-micro);
|
||||
font-weight: var(--font-weight-bold);
|
||||
margin-left: var(--space-smaller);
|
||||
padding: var(--space-zero) var(--space-smaller);
|
||||
line-height: var(--font-size-small);
|
||||
}
|
||||
</style>
|
||||
|
||||
+42
-154
@@ -1,46 +1,57 @@
|
||||
<template>
|
||||
<li v-show="isMenuItemVisible" class="sidebar-item">
|
||||
<div v-if="hasSubMenu" class="secondary-menu--wrap">
|
||||
<span class="secondary-menu--header fs-small">
|
||||
<li v-show="isMenuItemVisible" class="mt-1">
|
||||
<div v-if="hasSubMenu" class="flex justify-between">
|
||||
<span
|
||||
class="text-sm text-slate-700 dark:text-slate-200 font-semibold my-2 px-2 pt-1"
|
||||
>
|
||||
{{ $t(`SIDEBAR.${menuItem.label}`) }}
|
||||
</span>
|
||||
<div v-if="menuItem.showNewButton" class="submenu-icons">
|
||||
<div v-if="menuItem.showNewButton" class="flex items-center">
|
||||
<woot-button
|
||||
size="tiny"
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
icon="add"
|
||||
class="submenu-icon"
|
||||
class="p-0 ml-2"
|
||||
@click="onClickOpen"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<router-link
|
||||
v-else
|
||||
class="secondary-menu--title secondary-menu--link fs-small"
|
||||
class="rounded-lg leading-4 font-medium flex items-center p-2 m-0 text-sm text-slate-700 dark:text-slate-100 hover:bg-slate-25 dark:hover:bg-slate-800"
|
||||
:class="computedClass"
|
||||
:to="menuItem && menuItem.toState"
|
||||
>
|
||||
<fluent-icon
|
||||
:icon="menuItem.icon"
|
||||
class="secondary-menu--icon"
|
||||
class="min-w-[1rem] mr-1.5 rtl:mr-0 rtl:ml-1.5"
|
||||
size="14"
|
||||
/>
|
||||
{{ $t(`SIDEBAR.${menuItem.label}`) }}
|
||||
<span v-if="showChildCount(menuItem.count)" class="count-view">
|
||||
<span
|
||||
v-if="showChildCount(menuItem.count)"
|
||||
class="rounded-md text-xxs font-medium mx-1 py-0 px-1"
|
||||
:class="{
|
||||
'text-slate-300 dark:text-slate-600': isCountZero && !isActiveView,
|
||||
'text-slate-600 dark:text-slate-50': !isCountZero && !isActiveView,
|
||||
'bg-woot-75 dark:bg-woot-200 text-woot-600 dark:text-woot-600': isActiveView,
|
||||
'bg-slate-50 dark:bg-slate-700': !isActiveView,
|
||||
}"
|
||||
>
|
||||
{{ `${menuItem.count}` }}
|
||||
</span>
|
||||
<span
|
||||
v-if="menuItem.beta"
|
||||
data-view-component="true"
|
||||
label="Beta"
|
||||
class="beta"
|
||||
class="px-1 mx-1 inline-block font-medium leading-4 border border-green-400 text-green-500 rounded-lg text-xxs"
|
||||
>
|
||||
{{ $t('SIDEBAR.BETA') }}
|
||||
</span>
|
||||
</router-link>
|
||||
|
||||
<ul v-if="hasSubMenu" class="nested vertical menu">
|
||||
<ul v-if="hasSubMenu" class="list-none ml-0 mb-0">
|
||||
<secondary-child-nav-item
|
||||
v-for="child in menuItem.children"
|
||||
:key="child.id"
|
||||
@@ -55,21 +66,21 @@
|
||||
/>
|
||||
<router-link
|
||||
v-if="showItem(menuItem)"
|
||||
v-slot="{ href, isActive, navigate }"
|
||||
v-slot="{ href, navigate }"
|
||||
:to="menuItem.toState"
|
||||
custom
|
||||
>
|
||||
<li class="menu-item--new">
|
||||
<a
|
||||
:href="href"
|
||||
class="button small link clear secondary"
|
||||
:class="{ 'is-active': isActive }"
|
||||
@click="e => newLinkClick(e, navigate)"
|
||||
>
|
||||
<fluent-icon icon="add" size="16" />
|
||||
<span class="button__content">
|
||||
<li class="pl-1">
|
||||
<a :href="href">
|
||||
<woot-button
|
||||
size="tiny"
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
icon="add"
|
||||
@click="e => newLinkClick(e, navigate)"
|
||||
>
|
||||
{{ $t(`SIDEBAR.${menuItem.newLinkTag}`) }}
|
||||
</span>
|
||||
</woot-button>
|
||||
</a>
|
||||
</li>
|
||||
</router-link>
|
||||
@@ -108,6 +119,12 @@ export default {
|
||||
isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount',
|
||||
globalConfig: 'globalConfig/get',
|
||||
}),
|
||||
isCountZero() {
|
||||
return this.menuItem.count === 0;
|
||||
},
|
||||
isActiveView() {
|
||||
return this.computedClass.includes('active-view');
|
||||
},
|
||||
hasSubMenu() {
|
||||
return !!this.menuItem.children;
|
||||
},
|
||||
@@ -178,7 +195,7 @@ export default {
|
||||
this.isUnattended ||
|
||||
this.isCurrentRoute
|
||||
) {
|
||||
return 'is-active';
|
||||
return 'bg-woot-25 dark:bg-slate-800 text-woot-500 dark:text-woot-500 hover:text-woot-500 dark:hover:text-woot-500 active-view';
|
||||
}
|
||||
if (this.hasSubMenu) {
|
||||
if (
|
||||
@@ -187,12 +204,12 @@ export default {
|
||||
this.isIntegrationsSettings ||
|
||||
this.isApplicationsSettings
|
||||
) {
|
||||
return 'is-active';
|
||||
return 'bg-woot-25 dark:bg-slate-800 text-woot-500 dark:text-woot-500 hover:text-woot-500 dark:hover:text-woot-500 active-view';
|
||||
}
|
||||
return ' ';
|
||||
return 'hover:text-slate-700 dark:hover:text-slate-100';
|
||||
}
|
||||
|
||||
return '';
|
||||
return 'hover:text-slate-700 dark:hover:text-slate-100';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -233,132 +250,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.sidebar-item {
|
||||
margin: var(--space-smaller) 0 0;
|
||||
}
|
||||
|
||||
.secondary-menu--wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: var(--space-small);
|
||||
}
|
||||
|
||||
.secondary-menu--header {
|
||||
color: var(--s-700);
|
||||
display: flex;
|
||||
font-weight: var(--font-weight-bold);
|
||||
line-height: var(--space-normal);
|
||||
margin: var(--space-small) 0;
|
||||
padding: 0 var(--space-small);
|
||||
}
|
||||
.secondary-menu--title {
|
||||
color: var(--s-600);
|
||||
display: flex;
|
||||
font-weight: var(--font-weight-medium);
|
||||
line-height: var(--space-normal);
|
||||
margin: var(--space-small) 0;
|
||||
padding: 0 var(--space-small);
|
||||
}
|
||||
|
||||
.secondary-menu--link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
padding: var(--space-small);
|
||||
font-weight: var(--font-weight-medium);
|
||||
border-radius: var(--border-radius-normal);
|
||||
color: var(--s-700);
|
||||
|
||||
&:hover {
|
||||
background: var(--s-25);
|
||||
color: var(--s-600);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: var(--w-300);
|
||||
}
|
||||
|
||||
&.router-link-exact-active,
|
||||
&.is-active {
|
||||
background: var(--w-25);
|
||||
color: var(--w-500);
|
||||
border-color: var(--w-25);
|
||||
}
|
||||
|
||||
&.is-active .count-view {
|
||||
background: var(--w-75);
|
||||
color: var(--w-600);
|
||||
}
|
||||
}
|
||||
|
||||
.secondary-menu--icon {
|
||||
margin-right: var(--space-smaller);
|
||||
min-width: var(--space-normal);
|
||||
}
|
||||
|
||||
.sub-menu-link {
|
||||
color: var(--s-600);
|
||||
}
|
||||
|
||||
.wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.label-color--display {
|
||||
border-radius: var(--space-smaller);
|
||||
height: var(--space-normal);
|
||||
margin-right: var(--space-small);
|
||||
min-width: var(--space-normal);
|
||||
width: var(--space-normal);
|
||||
}
|
||||
|
||||
.inbox-icon {
|
||||
position: relative;
|
||||
top: -1px;
|
||||
}
|
||||
|
||||
.sidebar-item .menu-item--new {
|
||||
padding: var(--space-small) 0;
|
||||
|
||||
.button {
|
||||
display: inline-flex;
|
||||
color: var(--s-500);
|
||||
}
|
||||
}
|
||||
|
||||
.beta {
|
||||
padding-right: var(--space-smaller) !important;
|
||||
padding-left: var(--space-smaller) !important;
|
||||
margin: 0 var(--space-smaller) !important;
|
||||
display: inline-block;
|
||||
font-size: var(--font-size-micro);
|
||||
font-weight: var(--font-weight-medium);
|
||||
line-height: 14px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2em;
|
||||
color: var(--g-800);
|
||||
border-color: var(--g-700);
|
||||
}
|
||||
|
||||
.count-view {
|
||||
background: var(--s-50);
|
||||
border-radius: var(--border-radius-normal);
|
||||
color: var(--s-600);
|
||||
font-size: var(--font-size-micro);
|
||||
font-weight: var(--font-weight-bold);
|
||||
margin: 0 var(--space-smaller);
|
||||
padding: var(--space-zero) var(--space-smaller);
|
||||
}
|
||||
|
||||
.submenu-icons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.submenu-icon {
|
||||
padding: 0;
|
||||
margin-left: var(--space-small);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
+21
-22
@@ -4,7 +4,6 @@ import Vuex from 'vuex';
|
||||
import VueI18n from 'vue-i18n';
|
||||
|
||||
import i18n from 'dashboard/i18n';
|
||||
|
||||
import WootModal from 'dashboard/components/Modal';
|
||||
import WootModalHeader from 'dashboard/components/ModalHeader';
|
||||
import FluentIcon from 'shared/components/FluentIcon/DashboardIcon';
|
||||
@@ -38,9 +37,7 @@ describe('accountSelctor', () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
const accountId = 1;
|
||||
const globalConfig = { createNewAccountFromDashboard: false };
|
||||
let store = null;
|
||||
|
||||
let actions = null;
|
||||
let modules = null;
|
||||
|
||||
@@ -49,44 +46,46 @@ describe('accountSelctor', () => {
|
||||
modules = {
|
||||
auth: {
|
||||
getters: {
|
||||
getCurrentAccountId: () => accountId,
|
||||
getCurrentAccountId: () => 1,
|
||||
getCurrentUser: () => currentUser,
|
||||
},
|
||||
},
|
||||
globalConfig: {
|
||||
getters: {
|
||||
'globalConfig/get': () => globalConfig,
|
||||
'globalConfig/get': () => ({ createNewAccountFromDashboard: false }),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
store = new Vuex.Store({
|
||||
actions,
|
||||
modules,
|
||||
});
|
||||
let store = new Vuex.Store({ actions, modules });
|
||||
accountSelector = mount(AccountSelector, {
|
||||
store,
|
||||
localVue,
|
||||
i18n: i18nConfig,
|
||||
propsData: {
|
||||
showAccountModal: true,
|
||||
},
|
||||
propsData: { showAccountModal: true },
|
||||
stubs: { WootButton: { template: '<button />' } },
|
||||
});
|
||||
});
|
||||
|
||||
it('title and sub title exist', () => {
|
||||
const headerComponent = accountSelector.findComponent(WootModalHeader);
|
||||
const topBar = headerComponent.find('.page-top-bar');
|
||||
const titleComponent = topBar.find('.page-sub-title');
|
||||
expect(titleComponent.text()).toBe('Switch Account');
|
||||
const subTitleComponent = topBar.find('p');
|
||||
expect(subTitleComponent.text()).toBe(
|
||||
'Select an account from the following list'
|
||||
);
|
||||
const title = headerComponent.findComponent({ ref: 'modalHeaderTitle' });
|
||||
expect(title.text()).toBe('Switch Account');
|
||||
const content = headerComponent.findComponent({
|
||||
ref: 'modalHeaderContent',
|
||||
});
|
||||
expect(content.text()).toBe('Select an account from the following list');
|
||||
});
|
||||
|
||||
it('first account item is checked', () => {
|
||||
const accountFirstItem = accountSelector.find('.account-selector svg');
|
||||
expect(accountFirstItem.exists()).toBe(true);
|
||||
const selectedAccountCheckmark = accountSelector.find(
|
||||
'#account-1 > button > svg'
|
||||
);
|
||||
expect(selectedAccountCheckmark.exists()).toBe(true);
|
||||
|
||||
const otherAccountCheckmark = accountSelector.find(
|
||||
'#account-2 > button > svg'
|
||||
);
|
||||
expect(otherAccountCheckmark.exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,10 +19,7 @@ localVue.component('woot-dropdown-menu', WootDropdownMenu);
|
||||
localVue.component('woot-dropdown-divider', WootDropdownDivider);
|
||||
localVue.component('woot-dropdown-item', WootDropdownItem);
|
||||
|
||||
const i18nConfig = new VueI18n({
|
||||
locale: 'en',
|
||||
messages: i18n,
|
||||
});
|
||||
const i18nConfig = new VueI18n({ locale: 'en', messages: i18n });
|
||||
|
||||
describe('AvailabilityStatus', () => {
|
||||
const currentAvailability = 'online';
|
||||
@@ -48,15 +45,13 @@ describe('AvailabilityStatus', () => {
|
||||
},
|
||||
};
|
||||
|
||||
store = new Vuex.Store({
|
||||
actions,
|
||||
modules,
|
||||
});
|
||||
store = new Vuex.Store({ actions, modules });
|
||||
|
||||
availabilityStatus = mount(AvailabilityStatus, {
|
||||
store,
|
||||
localVue,
|
||||
i18n: i18nConfig,
|
||||
stubs: { WootSwitch: { template: '<button />' } },
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -3,7 +3,9 @@ import SidemenuIcon from '../SidemenuIcon';
|
||||
|
||||
describe('SidemenuIcon', () => {
|
||||
test('matches snapshot', () => {
|
||||
const wrapper = shallowMount(SidemenuIcon);
|
||||
const wrapper = shallowMount(SidemenuIcon, {
|
||||
stubs: { WootButton: { template: '<button><slot /></button>' } },
|
||||
});
|
||||
expect(wrapper.vm).toBeTruthy();
|
||||
expect(wrapper.element).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SidemenuIcon matches snapshot 1`] = `
|
||||
<woot-button
|
||||
class="toggle-sidebar"
|
||||
<button
|
||||
class="-ml-3 text-black-900 dark:text-slate-300"
|
||||
color-scheme="secondary"
|
||||
icon="list"
|
||||
size="small"
|
||||
|
||||
@@ -52,8 +52,8 @@ export default {
|
||||
|
||||
<style lang="scss">
|
||||
.announcement-popup {
|
||||
max-width: 24rem;
|
||||
min-width: 16rem;
|
||||
max-width: 15rem;
|
||||
min-width: 10rem;
|
||||
display: flex;
|
||||
position: absolute;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="showSeparator" class="separator">
|
||||
OR
|
||||
</div>
|
||||
<a :href="getGoogleAuthUrl()">
|
||||
<button
|
||||
class="button expanded button__google_login"
|
||||
:class="{
|
||||
// Explicit checking to ensure no other value is used
|
||||
large: buttonSize === 'large',
|
||||
small: buttonSize === 'small',
|
||||
tiny: buttonSize === 'tiny',
|
||||
}"
|
||||
>
|
||||
<img
|
||||
src="/assets/images/auth/google.svg"
|
||||
alt="Google Logo"
|
||||
class="icon"
|
||||
/>
|
||||
<slot>{{ $t('LOGIN.OAUTH.GOOGLE_LOGIN') }}</slot>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const validButtonSizes = ['small', 'tiny', 'large'];
|
||||
|
||||
export default {
|
||||
props: {
|
||||
showSeparator: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
buttonSize: {
|
||||
type: String,
|
||||
default: undefined,
|
||||
validator: value =>
|
||||
validButtonSizes.includes(value) || value === undefined,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getGoogleAuthUrl() {
|
||||
// Ideally a request to /auth/google_oauth2 should be made
|
||||
// Creating the URL manually because the devise-token-auth with
|
||||
// omniauth has a standing issue on redirecting the post request
|
||||
// https://github.com/lynndylanhurley/devise_token_auth/issues/1466
|
||||
const baseUrl =
|
||||
'https://accounts.google.com/o/oauth2/auth/oauthchooseaccount';
|
||||
const clientId = window.chatwootConfig.googleOAuthClientId;
|
||||
const redirectUri = window.chatwootConfig.googleOAuthCallbackUrl;
|
||||
const responseType = 'code';
|
||||
const scope = 'email profile';
|
||||
|
||||
// Build the query string
|
||||
const queryString = new URLSearchParams({
|
||||
client_id: clientId,
|
||||
redirect_uri: redirectUri,
|
||||
response_type: responseType,
|
||||
scope: scope,
|
||||
}).toString();
|
||||
|
||||
// Construct the full URL
|
||||
return `${baseUrl}?${queryString}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.separator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: var(--space-two) var(--space-zero);
|
||||
gap: var(--space-one);
|
||||
color: var(--s-300);
|
||||
font-size: var(--font-size-small);
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: var(--s-100);
|
||||
}
|
||||
}
|
||||
.button__google_login {
|
||||
background: var(--white);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: var(--space-one);
|
||||
border: 1px solid var(--s-100);
|
||||
color: var(--b-800);
|
||||
}
|
||||
</style>
|
||||
@@ -13,9 +13,10 @@
|
||||
<div class="content-wrap">
|
||||
{{ content }}
|
||||
</div>
|
||||
<div class="image-wrap">
|
||||
<div v-if="src" class="image-wrap">
|
||||
<img :src="src" class="image" :class="{ activeimage: active }" />
|
||||
</div>
|
||||
<slot v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -52,9 +53,9 @@ export default {
|
||||
border: 1px solid var(--color-border);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 34rem;
|
||||
max-width: 38rem;
|
||||
min-width: 24rem;
|
||||
max-height: 21.25rem;
|
||||
max-width: 23.75rem;
|
||||
min-width: 15rem;
|
||||
|
||||
.header--wrap {
|
||||
background: var(--s-50);
|
||||
@@ -62,7 +63,7 @@ export default {
|
||||
border-top-left-radius: var(--border-radius-normal);
|
||||
border-top-right-radius: var(--border-radius-normal);
|
||||
display: flex;
|
||||
height: 4rem;
|
||||
height: 2.5rem;
|
||||
justify-content: space-between;
|
||||
padding: var(--space-small);
|
||||
width: 100%;
|
||||
|
||||
@@ -61,7 +61,7 @@ export default {
|
||||
}
|
||||
|
||||
span {
|
||||
--space-one-point-five: 1.5rem;
|
||||
--space-one-point-five: 0.9375rem;
|
||||
background-color: var(--white);
|
||||
border-radius: 100%;
|
||||
box-shadow: var(--toggle-button-box-shadow);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
delay: { show: 1500, hide: 0 },
|
||||
hideOnClick: true,
|
||||
}"
|
||||
class="time-ago"
|
||||
class="text-xxs text-black-600 leading-4 ml-auto hover:text-black-900"
|
||||
>
|
||||
<span>{{ `${createdAtTime} • ${lastActivityTime}` }}</span>
|
||||
</div>
|
||||
@@ -109,16 +109,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.time-ago {
|
||||
color: var(--b-600);
|
||||
font-size: var(--font-size-micro);
|
||||
font-weight: var(--font-weight-normal);
|
||||
line-height: var(--space-normal);
|
||||
margin-left: auto;
|
||||
|
||||
&:hover {
|
||||
color: var(--b-900);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -18,7 +18,11 @@
|
||||
:icon="icon"
|
||||
:icon-size="iconSize"
|
||||
/>
|
||||
<span v-if="$slots.default" class="button__content">
|
||||
<span
|
||||
v-if="$slots.default"
|
||||
class="button__content"
|
||||
:class="{ 'text-left rtl:text-right': size !== 'expanded' }"
|
||||
>
|
||||
<slot />
|
||||
</span>
|
||||
</button>
|
||||
|
||||
@@ -75,9 +75,11 @@ import { mixin as clickaway } from 'vue-clickaway';
|
||||
import OpenAPI from 'dashboard/api/integrations/openapi';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import { OPEN_AI_EVENTS } from 'dashboard/helper/AnalyticsHelper/events';
|
||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||
import { buildHotKeys } from 'shared/helpers/KeyboardHelpers';
|
||||
|
||||
export default {
|
||||
mixins: [alertMixin, clickaway],
|
||||
mixins: [alertMixin, clickaway, eventListenerMixins],
|
||||
props: {
|
||||
conversationId: {
|
||||
type: Number,
|
||||
@@ -101,6 +103,7 @@ export default {
|
||||
},
|
||||
showDropdown: false,
|
||||
activeTone: 'professional',
|
||||
initialMessage: '',
|
||||
tones: [
|
||||
{
|
||||
key: 'professional',
|
||||
@@ -138,7 +141,18 @@ export default {
|
||||
this.$store.dispatch('integrations/get');
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onKeyDownHandler(event) {
|
||||
const keyPattern = buildHotKeys(event);
|
||||
const shouldRevertTheContent =
|
||||
['meta+z', 'ctrl+z'].includes(keyPattern) && !!this.initialMessage;
|
||||
|
||||
if (shouldRevertTheContent) {
|
||||
this.$emit('replace-text', this.initialMessage);
|
||||
this.initialMessage = '';
|
||||
}
|
||||
},
|
||||
toggleDropdown() {
|
||||
this.showDropdown = !this.showDropdown;
|
||||
},
|
||||
@@ -167,6 +181,7 @@ export default {
|
||||
const {
|
||||
data: { message: generatedMessage },
|
||||
} = result;
|
||||
this.initialMessage = this.message;
|
||||
this.$emit('replace-text', generatedMessage || this.message);
|
||||
this.closeDropdown();
|
||||
this.recordAnalytics({ type, tone: this.activeTone });
|
||||
|
||||
@@ -75,7 +75,7 @@ export default {
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
margin-top: var(--space-normal);
|
||||
max-height: 20rem;
|
||||
max-height: 12.5rem;
|
||||
}
|
||||
|
||||
.preview-item {
|
||||
@@ -84,7 +84,7 @@ export default {
|
||||
background: var(--color-background-light);
|
||||
background: var(--b-50);
|
||||
border-radius: var(--border-radius-normal);
|
||||
width: 24rem;
|
||||
width: 15rem;
|
||||
padding: var(--space-smaller);
|
||||
margin-bottom: var(--space-one);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ export default {
|
||||
.option-item--inbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 3.8rem;
|
||||
height: 2.375rem;
|
||||
min-width: 0;
|
||||
padding: 0 var(--space-smaller);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
v-if="showSearchDropdownLabel"
|
||||
:account-labels="allLabels"
|
||||
:selected-labels="selectedLabels"
|
||||
:allow-creation="isAdmin"
|
||||
@add="addItem"
|
||||
@remove="removeItem"
|
||||
/>
|
||||
@@ -30,8 +31,15 @@
|
||||
|
||||
<script>
|
||||
import AddLabel from 'shared/components/ui/dropdown/AddLabel';
|
||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||
import LabelDropdown from 'shared/components/ui/label/LabelDropdown';
|
||||
import { mixin as clickaway } from 'vue-clickaway';
|
||||
import adminMixin from 'dashboard/mixins/isAdmin';
|
||||
import {
|
||||
buildHotKeys,
|
||||
isEscape,
|
||||
isActiveElementTypeable,
|
||||
} from 'shared/helpers/KeyboardHelpers';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -39,7 +47,7 @@ export default {
|
||||
LabelDropdown,
|
||||
},
|
||||
|
||||
mixins: [clickaway],
|
||||
mixins: [clickaway, adminMixin, eventListenerMixins],
|
||||
|
||||
props: {
|
||||
allLabels: {
|
||||
@@ -80,6 +88,18 @@ export default {
|
||||
closeDropdownLabel() {
|
||||
this.showSearchDropdownLabel = false;
|
||||
},
|
||||
|
||||
handleKeyEvents(e) {
|
||||
const keyPattern = buildHotKeys(e);
|
||||
|
||||
if (keyPattern === 'l' && !isActiveElementTypeable(e)) {
|
||||
this.toggleLabels();
|
||||
e.preventDefault();
|
||||
} else if (isEscape(e) && this.showSearchDropdownLabel) {
|
||||
this.closeDropdownLabel();
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<template>
|
||||
<div class="row loading-state">
|
||||
<h6 class="message">{{ message }}<span class="spinner" /></h6>
|
||||
<div class="flex items-center justify-center p-8">
|
||||
<h6
|
||||
class="block text-base text-center w-100 text-slate-800 dark:text-slate-300"
|
||||
>
|
||||
<span class="mr-3">{{ message }}</span>
|
||||
<span class="spinner" />
|
||||
</h6>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
@@ -225,8 +225,8 @@ export default {
|
||||
|
||||
<style lang="scss">
|
||||
.audio-wave-wrapper {
|
||||
min-height: 8rem;
|
||||
height: 8rem;
|
||||
min-height: 5rem;
|
||||
height: 5rem;
|
||||
}
|
||||
.video-js .vjs-control-bar {
|
||||
background-color: transparent;
|
||||
|
||||
@@ -468,8 +468,8 @@ export default {
|
||||
}
|
||||
|
||||
.ProseMirror-woot-style {
|
||||
min-height: 8rem;
|
||||
max-height: 12rem;
|
||||
min-height: 5rem;
|
||||
max-height: 7.5rem;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -230,8 +230,8 @@ export default {
|
||||
}
|
||||
|
||||
.ProseMirror-woot-style {
|
||||
min-height: 8rem;
|
||||
max-height: 12rem;
|
||||
min-height: 5rem;
|
||||
max-height: 7.5rem;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -241,6 +241,6 @@ export default {
|
||||
box-shadow: var(--shadow-large);
|
||||
border-radius: var(--border-radius-normal);
|
||||
border: 1px solid var(--color-border);
|
||||
min-width: 40rem;
|
||||
min-width: 25rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -365,6 +365,6 @@ export default {
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 8rem;
|
||||
font-size: 5rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -121,8 +121,7 @@ export default {
|
||||
.top-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
background: var(--b-50);
|
||||
@apply bg-black-50 dark:bg-slate-800;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
@@ -145,11 +144,11 @@ export default {
|
||||
|
||||
.button--reply {
|
||||
border-radius: 0;
|
||||
border-right: 1px solid var(--color-border);
|
||||
@apply border-r border-b-0 border-l-0 border-slate-50 dark:border-slate-700;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
border-right: 1px solid var(--color-border);
|
||||
@apply border-r border-slate-50 dark:border-slate-700;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +156,7 @@ export default {
|
||||
border-radius: 0;
|
||||
|
||||
&.is-active {
|
||||
border-right: 1px solid var(--color-border);
|
||||
@apply border-r border-b-0 border-slate-50 dark:border-slate-700;
|
||||
background: var(--y-50);
|
||||
}
|
||||
|
||||
|
||||
+8
-10
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<div :class="`status-badge status-badge__${status}`" />
|
||||
<div
|
||||
:class="
|
||||
`status-badge status-badge__${status} rounded-full w-2.5 h-2.5 mr-0.5 rtl:mr-0 rtl:ml-0.5 inline-flex`
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
@@ -9,21 +13,15 @@ export default {
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import '~dashboard/assets/scss/variables';
|
||||
.status-badge {
|
||||
width: var(--space-one);
|
||||
height: var(--space-one);
|
||||
margin-right: var(--space-micro);
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
&__online {
|
||||
background: var(--g-400);
|
||||
@apply bg-green-400;
|
||||
}
|
||||
&__offline {
|
||||
background: var(--s-500);
|
||||
@apply bg-slate-500;
|
||||
}
|
||||
&__busy {
|
||||
background: var(--y-500);
|
||||
@apply bg-yellow-500;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ export default {
|
||||
margin-top: var(--space-smaller);
|
||||
padding: var(--space-normal);
|
||||
right: 0;
|
||||
width: 21rem;
|
||||
width: 13.125rem;
|
||||
|
||||
span {
|
||||
font-size: var(--font-size-small);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="conversation-details-wrap"
|
||||
class="conversation-details-wrap bg-slate-25 dark:bg-slate-800"
|
||||
:class="{ 'with-border-right': !isOnExpandedLayout }"
|
||||
>
|
||||
<conversation-header
|
||||
@@ -23,7 +23,10 @@
|
||||
:show-badge="false"
|
||||
/>
|
||||
</woot-tabs>
|
||||
<div v-show="!activeIndex" class="messages-and-sidebar">
|
||||
<div
|
||||
v-show="!activeIndex"
|
||||
class="flex bg-slate-25 dark:bg-slate-800 m-0 h-full min-h-0"
|
||||
>
|
||||
<messages-view
|
||||
v-if="currentChat.id"
|
||||
:inbox-id="inboxId"
|
||||
@@ -139,16 +142,14 @@ export default {
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import '~dashboard/assets/scss/woot';
|
||||
|
||||
.conversation-details-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
background: var(--color-background-light);
|
||||
|
||||
&.with-border-right {
|
||||
border-right: 1px solid var(--color-border);
|
||||
@apply border-r border-slate-50 dark:border-slate-700;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,41 +159,29 @@ export default {
|
||||
min-height: var(--dashboard-app-tabs-height);
|
||||
}
|
||||
|
||||
.messages-and-sidebar {
|
||||
display: flex;
|
||||
background: var(--color-background-light);
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.conversation-sidebar-wrap {
|
||||
border-right: 1px solid var(--color-border);
|
||||
height: auto;
|
||||
flex: 0 0;
|
||||
z-index: var(--z-index-low);
|
||||
overflow: auto;
|
||||
@apply border-r border-slate-50 dark:border-slate-700;
|
||||
background: white;
|
||||
flex-basis: 100%;
|
||||
|
||||
@include breakpoint(medium up) {
|
||||
flex-basis: 28rem;
|
||||
flex-basis: 17.5rem;
|
||||
}
|
||||
|
||||
@include breakpoint(large up) {
|
||||
flex-basis: 30em;
|
||||
flex-basis: 18.75rem;
|
||||
}
|
||||
|
||||
@include breakpoint(xlarge up) {
|
||||
flex-basis: 31em;
|
||||
flex-basis: 19.375rem;
|
||||
}
|
||||
|
||||
@include breakpoint(xxlarge up) {
|
||||
flex-basis: 33rem;
|
||||
flex-basis: 20.625rem;
|
||||
}
|
||||
|
||||
@include breakpoint(xxxlarge up) {
|
||||
flex-basis: 40rem;
|
||||
flex-basis: 25rem;
|
||||
}
|
||||
|
||||
&::v-deep .contact--panel {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="conversation"
|
||||
class="conversation group border-t border-transparent"
|
||||
:class="{
|
||||
active: isActiveChat,
|
||||
'unread-chat': hasUnread,
|
||||
@@ -30,7 +30,9 @@
|
||||
:status="currentContact.availability_status"
|
||||
size="40px"
|
||||
/>
|
||||
<div class="conversation--details columns">
|
||||
<div
|
||||
class="conversation--details border-b group-last:border-transparent group-hover:border-transparent border-slate-50 dark:border-slate-800 columns"
|
||||
>
|
||||
<div class="conversation--metadata">
|
||||
<inbox-name v-if="showInboxName" :inbox="inbox" />
|
||||
<div class="conversation-metadata-attributes">
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<div class="conv-header">
|
||||
<div class="conversation-header--details">
|
||||
<div class="conv-header flex-col md:flex-row">
|
||||
<div
|
||||
class="flex-1 w-100 flex flex-col md:flex-row items-center justify-center"
|
||||
>
|
||||
<div class="user">
|
||||
<back-button v-if="showBackButton" :back-url="backButtonUrl" />
|
||||
<Thumbnail
|
||||
@@ -44,7 +46,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="header-actions-wrap"
|
||||
class="header-actions-wrap mt-3 lg:mt-0"
|
||||
:class="{ 'has-open-sidebar': isContactPanelOpen }"
|
||||
>
|
||||
<more-actions :conversation-id="currentChat.id" />
|
||||
@@ -159,27 +161,9 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~dashboard/assets/scss/woot';
|
||||
|
||||
.conv-header {
|
||||
flex: 0 0 var(--space-jumbo);
|
||||
flex-direction: row;
|
||||
|
||||
@include breakpoint(medium up) {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.conversation-header--details {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
|
||||
@include breakpoint(medium up) {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
||||
.option__desc {
|
||||
|
||||
@@ -116,7 +116,7 @@ export default {
|
||||
|
||||
img {
|
||||
margin: var(--space-normal);
|
||||
width: 10rem;
|
||||
width: 6.25rem;
|
||||
}
|
||||
|
||||
span {
|
||||
|
||||
@@ -520,7 +520,7 @@ export default {
|
||||
|
||||
.image,
|
||||
.video {
|
||||
max-width: 32rem;
|
||||
max-width: 20rem;
|
||||
padding: var(--space-micro);
|
||||
|
||||
> img,
|
||||
@@ -534,13 +534,13 @@ export default {
|
||||
}
|
||||
}
|
||||
.video {
|
||||
height: 18rem;
|
||||
height: 11.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-image.is-text > .message-text__wrap,
|
||||
&.is-video.is-text > .message-text__wrap {
|
||||
max-width: 32rem;
|
||||
max-width: 20rem;
|
||||
padding: var(--space-small) var(--space-normal);
|
||||
}
|
||||
|
||||
|
||||
@@ -430,22 +430,22 @@ export default {
|
||||
.modal-mask {
|
||||
&::v-deep {
|
||||
.ProseMirror-woot-style {
|
||||
max-height: 40rem;
|
||||
max-height: 25rem;
|
||||
}
|
||||
|
||||
.reply-box {
|
||||
border: 1px solid var(--color-border);
|
||||
max-width: 120rem;
|
||||
max-width: 75rem;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
.reply-box .reply-box__top {
|
||||
position: relative;
|
||||
min-height: 44rem;
|
||||
min-height: 27.5rem;
|
||||
}
|
||||
|
||||
.reply-box__top .input {
|
||||
min-height: 44rem;
|
||||
min-height: 27.5rem;
|
||||
}
|
||||
|
||||
.emoji-dialog {
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="features-item">
|
||||
<h2 class="block-title">
|
||||
<h2 class="block-title text-black-900 dark:text-slate-200">
|
||||
<span class="emoji">💬</span>
|
||||
<span class="conversation--title">{{
|
||||
$t('ONBOARDING.ALL_CONVERSATION.TITLE')
|
||||
@@ -41,7 +41,7 @@
|
||||
</p>
|
||||
</div>
|
||||
<div class="features-item">
|
||||
<h2 class="block-title">
|
||||
<h2 class="block-title text-black-900 dark:text-slate-200">
|
||||
<span class="emoji">👥</span>
|
||||
{{ $t('ONBOARDING.TEAM_MEMBERS.TITLE') }}
|
||||
</h2>
|
||||
@@ -53,7 +53,7 @@
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="features-item">
|
||||
<h2 class="block-title">
|
||||
<h2 class="block-title text-black-900 dark:text-slate-200">
|
||||
<span class="emoji">📥</span>{{ $t('ONBOARDING.INBOXES.TITLE') }}
|
||||
</h2>
|
||||
<p class="intro-body">
|
||||
@@ -64,7 +64,7 @@
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="features-item">
|
||||
<h2 class="block-title">
|
||||
<h2 class="block-title text-black-900 dark:text-slate-200">
|
||||
<span class="emoji">🔖</span>{{ $t('ONBOARDING.LABELS.TITLE') }}
|
||||
</h2>
|
||||
<p class="intro-body">
|
||||
@@ -112,7 +112,7 @@ export default {
|
||||
}
|
||||
|
||||
.scroll-wrap {
|
||||
padding: var(--space-larger) 13.6rem;
|
||||
padding: var(--space-larger) 8.5rem;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -6,8 +6,11 @@
|
||||
delay: { show: 1500, hide: 0 },
|
||||
hideOnClick: true,
|
||||
}"
|
||||
class="conversation-priority-mark"
|
||||
:class="{ urgent: priority === CONVERSATION_PRIORITY.URGENT }"
|
||||
class="shrink-0 rounded-xs inline-flex w-3 h-3 "
|
||||
:class="{
|
||||
'bg-red-50 text-red-500': isUrgent,
|
||||
'bg-slate-50 text-slate-600': !isUrgent,
|
||||
}"
|
||||
>
|
||||
<fluent-icon
|
||||
:icon="`priority-${priority.toLowerCase()}`"
|
||||
@@ -41,24 +44,9 @@ export default {
|
||||
`CONVERSATION.PRIORITY.OPTIONS.${this.priority.toUpperCase()}`
|
||||
);
|
||||
},
|
||||
isUrgent() {
|
||||
return this.priority === CONVERSATION_PRIORITY.URGENT;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.conversation-priority-mark {
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
background: var(--s-50);
|
||||
border-radius: var(--border-radius-small);
|
||||
color: var(--s-600);
|
||||
display: inline-flex;
|
||||
width: var(--space-snug);
|
||||
height: var(--space-snug);
|
||||
|
||||
&.urgent {
|
||||
background: var(--r-50);
|
||||
color: var(--r-500);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
v-if="showReplyHead"
|
||||
:cc-emails.sync="ccEmails"
|
||||
:bcc-emails.sync="bccEmails"
|
||||
:to-emails.sync="toEmails"
|
||||
/>
|
||||
<woot-audio-recorder
|
||||
v-if="showAudioRecorderEditor"
|
||||
@@ -238,6 +239,7 @@ export default {
|
||||
hasSlashCommand: false,
|
||||
bccEmails: '',
|
||||
ccEmails: '',
|
||||
toEmails: '',
|
||||
doAutoSaveDraft: () => {},
|
||||
showWhatsAppTemplatesModal: false,
|
||||
updateEditorSelectionWith: '',
|
||||
@@ -528,7 +530,7 @@ export default {
|
||||
this.replyType = REPLY_EDITOR_MODES.NOTE;
|
||||
}
|
||||
|
||||
this.setCCEmailFromLastChat();
|
||||
this.setCCAndToEmailsFromLastChat();
|
||||
},
|
||||
conversationIdByRoute(conversationId, oldConversationId) {
|
||||
if (conversationId !== oldConversationId) {
|
||||
@@ -562,7 +564,7 @@ export default {
|
||||
// working even if input/textarea is focussed.
|
||||
document.addEventListener('paste', this.onPaste);
|
||||
document.addEventListener('keydown', this.handleKeyEvents);
|
||||
this.setCCEmailFromLastChat();
|
||||
this.setCCAndToEmailsFromLastChat();
|
||||
this.doAutoSaveDraft = debounce(
|
||||
() => {
|
||||
this.saveDraft(this.conversationIdByRoute, this.replyType);
|
||||
@@ -844,6 +846,7 @@ export default {
|
||||
clearEmailField() {
|
||||
this.ccEmails = '';
|
||||
this.bccEmails = '';
|
||||
this.toEmails = '';
|
||||
},
|
||||
toggleEmojiPicker() {
|
||||
this.showEmojiPicker = !this.showEmojiPicker;
|
||||
@@ -1054,22 +1057,56 @@ export default {
|
||||
messagePayload.bccEmails = this.bccEmails;
|
||||
}
|
||||
|
||||
if (this.toEmails && !this.isOnPrivateNote) {
|
||||
messagePayload.toEmails = this.toEmails;
|
||||
}
|
||||
|
||||
return messagePayload;
|
||||
},
|
||||
setCcEmails(value) {
|
||||
this.bccEmails = value.bccEmails;
|
||||
this.ccEmails = value.ccEmails;
|
||||
},
|
||||
setCCEmailFromLastChat() {
|
||||
if (this.lastEmail) {
|
||||
const {
|
||||
content_attributes: { email: emailAttributes = {} },
|
||||
} = this.lastEmail;
|
||||
const cc = emailAttributes.cc || [];
|
||||
const bcc = emailAttributes.bcc || [];
|
||||
this.ccEmails = cc.join(', ');
|
||||
this.bccEmails = bcc.join(', ');
|
||||
setCCAndToEmailsFromLastChat() {
|
||||
if (!this.lastEmail) return;
|
||||
|
||||
const {
|
||||
content_attributes: { email: emailAttributes = {} },
|
||||
} = this.lastEmail;
|
||||
|
||||
// Retrieve the email of the current conversation's sender
|
||||
const conversationContact = this.currentChat?.meta?.sender?.email || '';
|
||||
let cc = [...emailAttributes.cc] || [];
|
||||
let to = [];
|
||||
|
||||
// there might be a situation where the current conversation will include a message from a third person,
|
||||
// and the current conversation contact is in CC.
|
||||
// This is an edge-case, reported here: CW-1511 [ONLY FOR INTERNAL REFERENCE]
|
||||
// So we remove the current conversation contact's email from the CC list if present
|
||||
if (cc.includes(conversationContact)) {
|
||||
cc = cc.filter(email => email !== conversationContact);
|
||||
}
|
||||
|
||||
// If the last incoming message sender is different from the conversation contact, add them to the "to"
|
||||
// and add the conversation contact to the CC
|
||||
if (!emailAttributes.from.includes(conversationContact)) {
|
||||
to.push(...emailAttributes.from);
|
||||
cc.push(conversationContact);
|
||||
}
|
||||
|
||||
// Remove the conversation contact's email from the BCC list if present
|
||||
let bcc = (emailAttributes.bcc || []).filter(
|
||||
email => email !== conversationContact
|
||||
);
|
||||
|
||||
// Ensure only unique email addresses are in the CC list
|
||||
bcc = [...new Set(bcc)];
|
||||
cc = [...new Set(cc)];
|
||||
to = [...new Set(to)];
|
||||
|
||||
this.ccEmails = cc.join(', ');
|
||||
this.bccEmails = bcc.join(', ');
|
||||
this.toEmails = to.join(', ');
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1107,8 +1144,7 @@ export default {
|
||||
}
|
||||
|
||||
.reply-box {
|
||||
border-top: 1px solid var(--color-border);
|
||||
background: white;
|
||||
@apply border-r border-slate-50 dark:border-slate-700 bg-white dark:bg-slate-900;
|
||||
|
||||
&.is-private {
|
||||
background: var(--y-50);
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="toEmails">
|
||||
<div class="input-group small" :class="{ error: $v.toEmailsVal.$error }">
|
||||
<label class="input-group-label">
|
||||
{{ $t('CONVERSATION.REPLYBOX.EMAIL_HEAD.TO') }}
|
||||
</label>
|
||||
<div class="input-group-field">
|
||||
<woot-input
|
||||
v-model.trim="$v.toEmailsVal.$model"
|
||||
type="text"
|
||||
:class="{ error: $v.toEmailsVal.$error }"
|
||||
:placeholder="$t('CONVERSATION.REPLYBOX.EMAIL_HEAD.CC.PLACEHOLDER')"
|
||||
@blur="onBlur"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group-wrap">
|
||||
<div class="input-group small" :class="{ error: $v.ccEmailsVal.$error }">
|
||||
<label class="input-group-label">
|
||||
@@ -53,6 +69,7 @@
|
||||
|
||||
<script>
|
||||
import { validEmailsByComma } from './helpers/emailHeadHelper';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
ccEmails: {
|
||||
@@ -63,12 +80,17 @@ export default {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
toEmails: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showBcc: false,
|
||||
ccEmailsVal: '',
|
||||
bccEmailsVal: '',
|
||||
toEmailsVal: '',
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@@ -82,10 +104,16 @@ export default {
|
||||
this.ccEmailsVal = newVal;
|
||||
}
|
||||
},
|
||||
toEmails(newVal) {
|
||||
if (newVal !== this.toEmailsVal) {
|
||||
this.toEmailsVal = newVal;
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.ccEmailsVal = this.ccEmails;
|
||||
this.bccEmailsVal = this.bccEmails;
|
||||
this.toEmailsVal = this.toEmails;
|
||||
},
|
||||
validations: {
|
||||
ccEmailsVal: {
|
||||
@@ -98,6 +126,11 @@ export default {
|
||||
return validEmailsByComma(value);
|
||||
},
|
||||
},
|
||||
toEmailsVal: {
|
||||
hasValidEmails(value) {
|
||||
return validEmailsByComma(value);
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleAddBcc() {
|
||||
@@ -107,6 +140,7 @@ export default {
|
||||
this.$v.$touch();
|
||||
this.$emit('update:bccEmails', this.bccEmailsVal);
|
||||
this.$emit('update:ccEmails', this.ccEmailsVal);
|
||||
this.$emit('update:toEmails', this.toEmailsVal);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -96,7 +96,7 @@ export default {
|
||||
left: 0;
|
||||
bottom: 100%;
|
||||
line-height: 1.2;
|
||||
max-height: 20rem;
|
||||
max-height: 12.5rem;
|
||||
overflow: auto;
|
||||
padding: var(--space-small) var(--space-small) 0 var(--space-small);
|
||||
position: absolute;
|
||||
|
||||
+1
-1
@@ -71,6 +71,6 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
.modal-content {
|
||||
padding: 2.5rem 3.2rem;
|
||||
padding: 1.5625rem 2rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ export default {
|
||||
.template__list-container {
|
||||
background-color: var(--s-25);
|
||||
border-radius: var(--border-radius-medium);
|
||||
max-height: 30rem;
|
||||
max-height: 18.75rem;
|
||||
overflow-y: auto;
|
||||
padding: var(--space-one);
|
||||
|
||||
|
||||
@@ -254,8 +254,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~dashboard/assets/scss/woot';
|
||||
|
||||
.right {
|
||||
.message-text--metadata {
|
||||
align-items: center;
|
||||
@@ -319,10 +317,6 @@ export default {
|
||||
text-align: center;
|
||||
font-size: var(--font-size-micro);
|
||||
margin-left: 0;
|
||||
|
||||
@include breakpoint(xlarge up) {
|
||||
margin-left: var(--space-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,15 +10,15 @@
|
||||
<letter v-else class="text-content" :html="message" />
|
||||
<button
|
||||
v-if="showQuoteToggle"
|
||||
class="quoted-text--button"
|
||||
class="text-slate-300 dark:text-slate-300 cursor-pointer text-xs py-1"
|
||||
@click="toggleQuotedContent"
|
||||
>
|
||||
<span v-if="showQuotedContent">
|
||||
<fluent-icon icon="chevron-up" class="fluent-icon" size="16" />
|
||||
<span v-if="showQuotedContent" class="flex items-center gap-0.5">
|
||||
<fluent-icon icon="chevron-up" size="16" />
|
||||
{{ $t('CHAT_LIST.HIDE_QUOTED_TEXT') }}
|
||||
</span>
|
||||
<span v-else>
|
||||
<fluent-icon icon="chevron-down" class="fluent-icon" size="16" />
|
||||
<span v-else class="flex items-center gap-0.5">
|
||||
<fluent-icon icon="chevron-down" size="16" />
|
||||
{{ $t('CHAT_LIST.SHOW_QUOTED_TEXT') }}
|
||||
</span>
|
||||
</button>
|
||||
@@ -104,25 +104,13 @@ export default {
|
||||
|
||||
.show--quoted {
|
||||
blockquote {
|
||||
display: block;
|
||||
@apply block;
|
||||
}
|
||||
}
|
||||
|
||||
.hide--quoted {
|
||||
blockquote {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.quoted-text--button {
|
||||
color: var(--s-400);
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-mini);
|
||||
padding-bottom: var(--space-small);
|
||||
padding-top: var(--space-small);
|
||||
|
||||
.fluent-icon {
|
||||
margin-bottom: var(--space-minus-smaller);
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user