Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce8702564f |
+19
-19
@@ -12,7 +12,7 @@ defaults: &defaults
|
||||
# Specify service dependencies here if necessary
|
||||
# CircleCI maintains a library of pre-built images
|
||||
# documented at https://circleci.com/docs/2.0/circleci-images/
|
||||
- image: cimg/postgres:15.3
|
||||
- image: cimg/postgres:14.1
|
||||
- image: cimg/redis:6.2.6
|
||||
environment:
|
||||
- RAILS_LOG_TO_STDOUT: false
|
||||
@@ -73,7 +73,7 @@ jobs:
|
||||
|
||||
- run:
|
||||
name: yarn
|
||||
command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn
|
||||
command: yarn install --cache-folder ~/.cache/yarn
|
||||
|
||||
# Store yarn / webpacker cache
|
||||
- save_cache:
|
||||
@@ -104,8 +104,9 @@ 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
|
||||
|
||||
@@ -116,7 +117,7 @@ jobs:
|
||||
- run:
|
||||
name: Rubocop
|
||||
command: bundle exec rubocop
|
||||
|
||||
|
||||
# - run:
|
||||
# name: Brakeman
|
||||
# command: bundle exec brakeman
|
||||
@@ -125,21 +126,6 @@ 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
|
||||
@@ -159,6 +145,20 @@ 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:
|
||||
|
||||
@@ -230,11 +230,3 @@ AZURE_APP_SECRET=
|
||||
## Change these values to fine tune performance
|
||||
# control the concurrency setting of sidekiq
|
||||
# SIDEKIQ_CONCURRENCY=10
|
||||
|
||||
|
||||
# AI powered features
|
||||
## OpenAI key
|
||||
# OPENAI_API_KEY=
|
||||
|
||||
# Sentiment analysis model file path
|
||||
SENTIMENT_FILE_PATH=
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# ref: https://github.com/amannn/action-semantic-pull-request
|
||||
# ensure PR title is in semantic format
|
||||
|
||||
name: "Lint PR"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
main:
|
||||
name: Validate PR title
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v5
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -18,12 +18,11 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:15.3
|
||||
image: postgres:10.8
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: ""
|
||||
POSTGRES_DB: postgres
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
ports:
|
||||
- 5432:5432
|
||||
# needed because the postgres container does not provide a healthcheck
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
# #
|
||||
# # This workflow will run specs related to response bot
|
||||
# # This can only be activated in installations Where vector extension is available.
|
||||
# #
|
||||
|
||||
name: Run Response Bot spec
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
- master
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-20.04
|
||||
services:
|
||||
postgres:
|
||||
image: ankane/pgvector
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: ""
|
||||
POSTGRES_DB: postgres
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
ports:
|
||||
- 5432:5432
|
||||
# needed because the postgres container does not provide a healthcheck
|
||||
# tmpfs makes DB faster by using RAM
|
||||
options: >-
|
||||
--mount type=tmpfs,destination=/var/lib/postgresql/data
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
options: --entrypoint redis-server
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: yarn
|
||||
run: yarn install
|
||||
|
||||
- name: Create database
|
||||
run: bundle exec rake db:create
|
||||
|
||||
- name: Seed database
|
||||
run: bundle exec rake db:schema:load
|
||||
|
||||
- name: Enable ResponseBotService in installation
|
||||
run: RAILS_ENV=test bundle exec rails runner "Features::ResponseBotService.new.enable_in_installation"
|
||||
|
||||
# Run Response Bot specs
|
||||
- name: Run backend tests
|
||||
run: |
|
||||
bundle exec rspec spec/enterprise/controllers/api/v1/accounts/response_sources_controller_spec.rb spec/enterprise/controllers/enterprise/api/v1/accounts/inboxes_controller_spec.rb:47 --profile=10 --format documentation
|
||||
|
||||
- name: Upload rails log folder
|
||||
uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: rails-log-folder
|
||||
path: log
|
||||
@@ -1,38 +0,0 @@
|
||||
name: Run Size Limit Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: yarn
|
||||
run: yarn install
|
||||
|
||||
- name: Strip enterprise code
|
||||
run: |
|
||||
rm -rf enterprise
|
||||
rm -rf spec/enterprise
|
||||
|
||||
- name: Run asset compile
|
||||
run: bundle exec rake assets:precompile
|
||||
|
||||
- name: Size Check
|
||||
run: yarn run size
|
||||
@@ -74,5 +74,3 @@ yalc.lock
|
||||
/yarn-error.log
|
||||
yarn-debug.log*
|
||||
.yarn-integrity
|
||||
|
||||
/storybook-static
|
||||
@@ -87,7 +87,6 @@ Style/ClassAndModuleChildren:
|
||||
EnforcedStyle: compact
|
||||
Exclude:
|
||||
- 'config/application.rb'
|
||||
- 'config/initializers/monkey_patches/*'
|
||||
Style/MapToHash:
|
||||
Enabled: false
|
||||
Style/HashSyntax:
|
||||
|
||||
@@ -4,7 +4,7 @@ ruby '3.2.2'
|
||||
|
||||
##-- base gems for rails --##
|
||||
gem 'rack-cors', require: 'rack/cors'
|
||||
gem 'rails', '~> 7.0.5.1'
|
||||
gem 'rails', '~> 7'
|
||||
# Reduces boot times through caching; required in config/boot.rb
|
||||
gem 'bootsnap', require: false
|
||||
|
||||
@@ -74,8 +74,7 @@ gem 'devise_token_auth'
|
||||
gem 'jwt'
|
||||
gem 'pundit'
|
||||
# super admin
|
||||
gem 'administrate', '>= 0.19.0'
|
||||
gem 'administrate-field-active_storage'
|
||||
gem 'administrate'
|
||||
|
||||
##--- gems for pubsub service ---##
|
||||
# https://karolgalanciak.com/blog/2019/11/30/from-activerecord-callbacks-to-publish-slash-subscribe-pattern-and-event-driven-design/
|
||||
@@ -108,9 +107,9 @@ gem 'elastic-apm', require: false
|
||||
gem 'newrelic_rpm', require: false
|
||||
gem 'newrelic-sidekiq-metrics', require: false
|
||||
gem 'scout_apm', require: false
|
||||
gem 'sentry-rails', '>= 5.10.0', require: false
|
||||
gem 'sentry-rails', require: false
|
||||
gem 'sentry-ruby', require: false
|
||||
gem 'sentry-sidekiq', '>= 5.10.0', require: false
|
||||
gem 'sentry-sidekiq', require: false
|
||||
|
||||
##-- background job processing --##
|
||||
gem 'sidekiq'
|
||||
@@ -165,16 +164,6 @@ gem 'omniauth'
|
||||
gem 'omniauth-google-oauth2'
|
||||
gem 'omniauth-rails_csrf_protection', '~> 1.0'
|
||||
|
||||
## Gems for reponse bot
|
||||
# adds cosine similarity to postgres using vector extension
|
||||
gem 'neighbor'
|
||||
gem 'pgvector'
|
||||
# Convert Website HTML to Markdown
|
||||
gem 'reverse_markdown'
|
||||
|
||||
# Sentiment analysis
|
||||
gem 'informers'
|
||||
|
||||
### Gems required only in specific deployment environments ###
|
||||
##############################################################
|
||||
|
||||
@@ -220,7 +209,6 @@ group :development, :test do
|
||||
gem 'bundle-audit', require: false
|
||||
gem 'byebug', platform: :mri
|
||||
gem 'climate_control'
|
||||
gem 'debug', '~> 1.8'
|
||||
gem 'factory_bot_rails'
|
||||
gem 'listen'
|
||||
gem 'mock_redis'
|
||||
|
||||
+87
-125
@@ -33,70 +33,70 @@ GIT
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (7.0.5.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
actioncable (7.0.4.3)
|
||||
actionpack (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
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)
|
||||
actionmailbox (7.0.4.3)
|
||||
actionpack (= 7.0.4.3)
|
||||
activejob (= 7.0.4.3)
|
||||
activerecord (= 7.0.4.3)
|
||||
activestorage (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
mail (>= 2.7.1)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
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)
|
||||
actionmailer (7.0.4.3)
|
||||
actionpack (= 7.0.4.3)
|
||||
actionview (= 7.0.4.3)
|
||||
activejob (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (7.0.5.1)
|
||||
actionview (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
rack (~> 2.0, >= 2.2.4)
|
||||
actionpack (7.0.4.3)
|
||||
actionview (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
rack (~> 2.0, >= 2.2.0)
|
||||
rack-test (>= 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||
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)
|
||||
actiontext (7.0.4.3)
|
||||
actionpack (= 7.0.4.3)
|
||||
activerecord (= 7.0.4.3)
|
||||
activestorage (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
actionview (7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
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.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
activejob (7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
globalid (>= 0.3.6)
|
||||
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)
|
||||
activemodel (7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
activerecord (7.0.4.3)
|
||||
activemodel (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
activerecord-import (1.4.1)
|
||||
activerecord (>= 4.2)
|
||||
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)
|
||||
activestorage (7.0.4.3)
|
||||
actionpack (= 7.0.4.3)
|
||||
activejob (= 7.0.4.3)
|
||||
activerecord (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
marcel (~> 1.0)
|
||||
mini_mime (>= 1.1.0)
|
||||
activesupport (7.0.5.1)
|
||||
activesupport (7.0.4.3)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
@@ -105,7 +105,7 @@ GEM
|
||||
activerecord (>= 6.0, < 7.1)
|
||||
addressable (2.8.4)
|
||||
public_suffix (>= 2.0.2, < 6.0)
|
||||
administrate (0.19.0)
|
||||
administrate (0.18.0)
|
||||
actionpack (>= 5.0)
|
||||
actionview (>= 5.0)
|
||||
activerecord (>= 5.0)
|
||||
@@ -113,9 +113,6 @@ GEM
|
||||
kaminari (>= 1.0)
|
||||
sassc-rails (~> 2.1)
|
||||
selectize-rails (~> 0.6)
|
||||
administrate-field-active_storage (0.4.2)
|
||||
administrate (>= 0.2.2)
|
||||
rails (>= 7.0)
|
||||
annotate (3.2.0)
|
||||
activerecord (>= 3.2, < 8.0)
|
||||
rake (>= 10.4, < 14.0)
|
||||
@@ -145,7 +142,6 @@ GEM
|
||||
statsd-ruby (~> 1.1)
|
||||
bcrypt (3.1.18)
|
||||
bindex (0.8.1)
|
||||
blingfire (0.1.8)
|
||||
bootsnap (1.16.0)
|
||||
msgpack (~> 1.2)
|
||||
brakeman (5.4.1)
|
||||
@@ -164,7 +160,7 @@ GEM
|
||||
coderay (1.1.3)
|
||||
commonmarker (0.23.9)
|
||||
concurrent-ruby (1.2.2)
|
||||
connection_pool (2.4.1)
|
||||
connection_pool (2.4.0)
|
||||
crack (0.4.5)
|
||||
rexml
|
||||
crass (1.0.6)
|
||||
@@ -184,9 +180,6 @@ GEM
|
||||
libddwaf (~> 1.8.2.0.0)
|
||||
msgpack
|
||||
debase-ruby_core_source (3.2.0)
|
||||
debug (1.8.0)
|
||||
irb (>= 1.5.0)
|
||||
reline (>= 0.3.1)
|
||||
declarative (0.0.20)
|
||||
devise (4.9.2)
|
||||
bcrypt (~> 3.0)
|
||||
@@ -360,23 +353,16 @@ GEM
|
||||
mini_mime (>= 1.0.0)
|
||||
multi_xml (>= 0.5.2)
|
||||
httpclient (2.8.3)
|
||||
i18n (1.14.1)
|
||||
i18n (1.13.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
image_processing (1.12.2)
|
||||
mini_magick (>= 4.9.5, < 5)
|
||||
ruby-vips (>= 2.0.17, < 3)
|
||||
informers (0.2.0)
|
||||
blingfire (>= 0.1.7)
|
||||
numo-narray
|
||||
onnxruntime (>= 0.5.1)
|
||||
io-console (0.6.0)
|
||||
irb (1.7.2)
|
||||
reline (>= 0.3.6)
|
||||
jbuilder (2.11.5)
|
||||
actionview (>= 5.0.0)
|
||||
activesupport (>= 5.0.0)
|
||||
jmespath (1.6.2)
|
||||
jquery-rails (4.6.0)
|
||||
jquery-rails (4.5.1)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
@@ -434,9 +420,9 @@ GEM
|
||||
activesupport (>= 4)
|
||||
railties (>= 4)
|
||||
request_store (~> 1.0)
|
||||
loofah (2.21.3)
|
||||
loofah (2.20.0)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
nokogiri (>= 1.5.9)
|
||||
mail (2.8.1)
|
||||
mini_mime (>= 0.1.1)
|
||||
net-imap
|
||||
@@ -451,19 +437,17 @@ GEM
|
||||
mime-types-data (3.2023.0218.1)
|
||||
mini_magick (4.12.0)
|
||||
mini_mime (1.1.2)
|
||||
mini_portile2 (2.8.4)
|
||||
minitest (5.18.1)
|
||||
mini_portile2 (2.8.2)
|
||||
minitest (5.18.0)
|
||||
mock_redis (0.36.0)
|
||||
ruby2_keywords
|
||||
msgpack (1.7.0)
|
||||
multi_json (1.15.0)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.3.0)
|
||||
neighbor (0.2.3)
|
||||
activerecord (>= 5.2)
|
||||
net-http-persistent (4.0.2)
|
||||
connection_pool (~> 2.2)
|
||||
net-imap (0.3.6)
|
||||
net-imap (0.3.4)
|
||||
date
|
||||
net-protocol
|
||||
net-pop (0.1.2)
|
||||
@@ -478,16 +462,15 @@ GEM
|
||||
sidekiq
|
||||
newrelic_rpm (8.16.0)
|
||||
nio4r (2.5.9)
|
||||
nokogiri (1.15.3)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
nokogiri (1.14.3)
|
||||
mini_portile2 (~> 2.8.0)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.15.3-arm64-darwin)
|
||||
nokogiri (1.14.3-arm64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.15.3-x86_64-darwin)
|
||||
nokogiri (1.14.3-x86_64-darwin)
|
||||
racc (~> 1.4)
|
||||
nokogiri (1.15.3-x86_64-linux)
|
||||
nokogiri (1.14.3-x86_64-linux)
|
||||
racc (~> 1.4)
|
||||
numo-narray (0.9.2.1)
|
||||
oauth (1.1.0)
|
||||
oauth-tty (~> 1.0, >= 1.0.1)
|
||||
snaky_hash (~> 2.0)
|
||||
@@ -516,14 +499,6 @@ GEM
|
||||
omniauth-rails_csrf_protection (1.0.1)
|
||||
actionpack (>= 4.2)
|
||||
omniauth (~> 2.0)
|
||||
onnxruntime (0.7.6)
|
||||
ffi
|
||||
onnxruntime (0.7.6-arm64-darwin)
|
||||
ffi
|
||||
onnxruntime (0.7.6-x86_64-darwin)
|
||||
ffi
|
||||
onnxruntime (0.7.6-x86_64-linux)
|
||||
ffi
|
||||
openssl (3.1.0)
|
||||
orm_adapter (0.5.0)
|
||||
os (1.1.4)
|
||||
@@ -534,7 +509,6 @@ GEM
|
||||
pg_search (2.3.6)
|
||||
activerecord (>= 5.2)
|
||||
activesupport (>= 5.2)
|
||||
pgvector (0.1.1)
|
||||
procore-sift (1.0.0)
|
||||
activerecord (>= 6.1)
|
||||
pry (0.14.2)
|
||||
@@ -548,7 +522,7 @@ GEM
|
||||
pundit (2.3.0)
|
||||
activesupport (>= 3.0.0)
|
||||
raabro (1.4.0)
|
||||
racc (1.7.1)
|
||||
racc (1.6.2)
|
||||
rack (2.2.7)
|
||||
rack-attack (6.6.1)
|
||||
rack (>= 1.0, < 3)
|
||||
@@ -563,30 +537,28 @@ GEM
|
||||
rack-test (2.1.0)
|
||||
rack (>= 1.3)
|
||||
rack-timeout (0.6.3)
|
||||
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)
|
||||
rails (7.0.4.3)
|
||||
actioncable (= 7.0.4.3)
|
||||
actionmailbox (= 7.0.4.3)
|
||||
actionmailer (= 7.0.4.3)
|
||||
actionpack (= 7.0.4.3)
|
||||
actiontext (= 7.0.4.3)
|
||||
actionview (= 7.0.4.3)
|
||||
activejob (= 7.0.4.3)
|
||||
activemodel (= 7.0.4.3)
|
||||
activerecord (= 7.0.4.3)
|
||||
activestorage (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 7.0.5.1)
|
||||
rails-dom-testing (2.1.1)
|
||||
activesupport (>= 5.0.0)
|
||||
minitest
|
||||
railties (= 7.0.4.3)
|
||||
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.1)
|
||||
actionpack (= 7.0.5.1)
|
||||
activesupport (= 7.0.5.1)
|
||||
rails-html-sanitizer (1.5.0)
|
||||
loofah (~> 2.19, >= 2.19.1)
|
||||
railties (7.0.4.3)
|
||||
actionpack (= 7.0.4.3)
|
||||
activesupport (= 7.0.4.3)
|
||||
method_source
|
||||
rake (>= 12.2)
|
||||
thor (~> 1.0)
|
||||
@@ -603,8 +575,6 @@ GEM
|
||||
redis-namespace (1.10.0)
|
||||
redis (>= 4)
|
||||
regexp_parser (2.8.0)
|
||||
reline (0.3.6)
|
||||
io-console (~> 0.5)
|
||||
representable (3.2.0)
|
||||
declarative (< 0.1.0)
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
@@ -620,8 +590,6 @@ GEM
|
||||
mime-types (>= 1.16, < 4.0)
|
||||
netrc (~> 0.8)
|
||||
retriable (3.1.2)
|
||||
reverse_markdown (2.1.1)
|
||||
nokogiri
|
||||
rexml (3.2.5)
|
||||
rspec-core (3.12.2)
|
||||
rspec-support (~> 3.12.0)
|
||||
@@ -697,18 +665,18 @@ GEM
|
||||
activesupport (>= 4)
|
||||
selectize-rails (0.12.6)
|
||||
semantic_range (3.0.0)
|
||||
sentry-rails (5.10.0)
|
||||
sentry-rails (5.9.0)
|
||||
railties (>= 5.0)
|
||||
sentry-ruby (~> 5.10.0)
|
||||
sentry-ruby (5.10.0)
|
||||
sentry-ruby (~> 5.9.0)
|
||||
sentry-ruby (5.9.0)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
sentry-sidekiq (5.10.0)
|
||||
sentry-ruby (~> 5.10.0)
|
||||
sentry-sidekiq (5.9.0)
|
||||
sentry-ruby (~> 5.9.0)
|
||||
sidekiq (>= 3.0)
|
||||
sexp_processor (4.17.0)
|
||||
shoulda-matchers (5.3.0)
|
||||
activesupport (>= 5.2.0)
|
||||
sidekiq (7.1.2)
|
||||
sidekiq (7.1.0)
|
||||
concurrent-ruby (< 2)
|
||||
connection_pool (>= 2.3.0)
|
||||
rack (>= 2.2.4)
|
||||
@@ -754,12 +722,12 @@ GEM
|
||||
stripe (8.5.0)
|
||||
telephone_number (1.4.20)
|
||||
test-prof (1.2.1)
|
||||
thor (1.2.2)
|
||||
tilt (2.2.0)
|
||||
thor (1.2.1)
|
||||
tilt (2.1.0)
|
||||
time_diff (0.3.0)
|
||||
activesupport
|
||||
i18n
|
||||
timeout (0.4.0)
|
||||
timeout (0.3.2)
|
||||
trailblazer-option (0.1.2)
|
||||
twilio-ruby (5.77.0)
|
||||
faraday (>= 0.9, < 3.0)
|
||||
@@ -829,8 +797,7 @@ DEPENDENCIES
|
||||
active_record_query_trace
|
||||
activerecord-import
|
||||
acts-as-taggable-on
|
||||
administrate (>= 0.19.0)
|
||||
administrate-field-active_storage
|
||||
administrate
|
||||
annotate
|
||||
attr_extras
|
||||
audited (~> 5.3)
|
||||
@@ -849,7 +816,6 @@ DEPENDENCIES
|
||||
cypress-on-rails
|
||||
database_cleaner
|
||||
ddtrace
|
||||
debug (~> 1.8)
|
||||
devise
|
||||
devise-secure_password!
|
||||
devise_token_auth
|
||||
@@ -875,7 +841,6 @@ DEPENDENCIES
|
||||
hashie
|
||||
html2text!
|
||||
image_processing
|
||||
informers
|
||||
jbuilder
|
||||
json_refs
|
||||
json_schemer
|
||||
@@ -889,7 +854,6 @@ DEPENDENCIES
|
||||
lograge (~> 0.12.0)
|
||||
maxminddb
|
||||
mock_redis
|
||||
neighbor
|
||||
newrelic-sidekiq-metrics
|
||||
newrelic_rpm
|
||||
omniauth
|
||||
@@ -898,7 +862,6 @@ DEPENDENCIES
|
||||
omniauth-rails_csrf_protection (~> 1.0)
|
||||
pg
|
||||
pg_search
|
||||
pgvector
|
||||
procore-sift
|
||||
pry-rails
|
||||
puma
|
||||
@@ -907,12 +870,11 @@ DEPENDENCIES
|
||||
rack-cors
|
||||
rack-mini-profiler
|
||||
rack-timeout
|
||||
rails (~> 7.0.5.1)
|
||||
rails (~> 7)
|
||||
redis
|
||||
redis-namespace
|
||||
responders
|
||||
rest-client
|
||||
reverse_markdown
|
||||
rspec-rails
|
||||
rspec_junit_formatter
|
||||
rubocop
|
||||
@@ -922,9 +884,9 @@ DEPENDENCIES
|
||||
scout_apm
|
||||
scss_lint
|
||||
seed_dump
|
||||
sentry-rails (>= 5.10.0)
|
||||
sentry-rails
|
||||
sentry-ruby
|
||||
sentry-sidekiq (>= 5.10.0)
|
||||
sentry-sidekiq
|
||||
shoulda-matchers
|
||||
sidekiq
|
||||
sidekiq-cron
|
||||
@@ -954,4 +916,4 @@ RUBY VERSION
|
||||
ruby 3.2.2p185
|
||||
|
||||
BUNDLED WITH
|
||||
2.4.6
|
||||
2.4.10
|
||||
|
||||
@@ -30,23 +30,9 @@ burn:
|
||||
bundle && yarn
|
||||
|
||||
run:
|
||||
@if [ -f ./.overmind.sock ]; then \
|
||||
echo "Overmind is already running. Use 'make force_run' to start a new instance."; \
|
||||
else \
|
||||
overmind start -f Procfile.dev; \
|
||||
fi
|
||||
|
||||
force_run:
|
||||
rm -f ./.overmind.sock
|
||||
overmind start -f Procfile.dev
|
||||
|
||||
debug:
|
||||
overmind connect backend
|
||||
|
||||
debug_worker:
|
||||
overmind connect worker
|
||||
|
||||
docker:
|
||||
docker build -t $(APP_NAME) -f ./docker/Dockerfile .
|
||||
|
||||
.PHONY: setup db_create db_migrate db_seed db console server burn docker run force_run debug debug_worker
|
||||
.PHONY: setup db_create db_migrate db_seed db console server burn docker run
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
//= link_tree ../images
|
||||
//= link administrate/application.css
|
||||
//= link administrate/application.js
|
||||
//= link administrate-field-active_storage/application.css
|
||||
//= link dashboardChart.js
|
||||
//= link secretField.js
|
||||
|
||||
@@ -11,7 +11,7 @@ function prepareData(data) {
|
||||
|
||||
function getChartOptions() {
|
||||
var fontFamily =
|
||||
'PlusJakarta,-apple-system,system-ui,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif';
|
||||
'Inter,-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: PlusJakarta, Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
||||
$base-font-family: 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: 16px !default;
|
||||
$base-font-size: 10px !default;
|
||||
|
||||
$base-line-height: 1.5 !default;
|
||||
$heading-line-height: 1.2 !default;
|
||||
|
||||
@@ -48,22 +48,17 @@ class Messages::MessageBuilder
|
||||
def process_emails
|
||||
return unless @conversation.inbox&.inbox_type == 'Email'
|
||||
|
||||
cc_emails = process_email_string(@params[:cc_emails])
|
||||
bcc_emails = process_email_string(@params[:bcc_emails])
|
||||
to_emails = process_email_string(@params[:to_emails])
|
||||
cc_emails = []
|
||||
cc_emails = @params[:cc_emails].gsub(/\s+/, '').split(',') if @params[:cc_emails].present?
|
||||
|
||||
all_email_addresses = cc_emails + bcc_emails + to_emails
|
||||
bcc_emails = []
|
||||
bcc_emails = @params[:bcc_emails].gsub(/\s+/, '').split(',') if @params[:bcc_emails].present?
|
||||
|
||||
all_email_addresses = cc_emails + bcc_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)
|
||||
|
||||
@@ -20,7 +20,7 @@ class V2::ReportBuilder
|
||||
|
||||
# For backward compatible with old report
|
||||
def build
|
||||
if %w[avg_first_response_time avg_resolution_time reply_time].include?(params[:metric])
|
||||
if %w[avg_first_response_time avg_resolution_time].include?(params[:metric])
|
||||
timeseries.each_with_object([]) do |p, arr|
|
||||
arr << { value: p[1], timestamp: p[0].in_time_zone(@timezone).to_i, count: @grouped_values.count[p[0]] }
|
||||
end
|
||||
@@ -33,19 +33,18 @@ class V2::ReportBuilder
|
||||
|
||||
def summary
|
||||
{
|
||||
conversations_count: conversations.count,
|
||||
incoming_messages_count: incoming_messages.count,
|
||||
outgoing_messages_count: outgoing_messages.count,
|
||||
conversations_count: conversations_count.values.sum,
|
||||
incoming_messages_count: incoming_messages_count.values.sum,
|
||||
outgoing_messages_count: outgoing_messages_count.values.sum,
|
||||
avg_first_response_time: avg_first_response_time_summary,
|
||||
avg_resolution_time: avg_resolution_time_summary,
|
||||
resolutions_count: resolutions.count,
|
||||
reply_time: reply_time_summary
|
||||
resolutions_count: resolutions_count.values.sum
|
||||
}
|
||||
end
|
||||
|
||||
def conversation_metrics
|
||||
if params[:type].equal?(:account)
|
||||
live_conversations
|
||||
conversations
|
||||
else
|
||||
agent_metrics.sort_by { |hash| hash[:metric][:open] }.reverse
|
||||
end
|
||||
@@ -90,16 +89,17 @@ class V2::ReportBuilder
|
||||
email: @user.email,
|
||||
thumbnail: @user.avatar_url,
|
||||
availability: account_user.availability_status,
|
||||
metric: live_conversations
|
||||
metric: conversations
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def live_conversations
|
||||
def conversations
|
||||
@open_conversations = scope.conversations.where(account_id: @account.id).open
|
||||
first_response_count = @account.reporting_events.where(name: 'first_response', conversation_id: @open_conversations.pluck('id')).count
|
||||
metric = {
|
||||
open: @open_conversations.count,
|
||||
unattended: @open_conversations.unattended.count
|
||||
unattended: @open_conversations.count - first_response_count
|
||||
}
|
||||
metric[:unassigned] = @open_conversations.unassigned.count if params[:type].equal?(:account)
|
||||
metric
|
||||
|
||||
@@ -18,11 +18,7 @@ class Api::V1::Accounts::Channels::TwilioChannelsController < Api::V1::Accounts:
|
||||
end
|
||||
|
||||
def authenticate_twilio
|
||||
client = if permitted_params[:api_key_sid].present?
|
||||
Twilio::REST::Client.new(permitted_params[:api_key_sid], permitted_params[:auth_token], permitted_params[:account_sid])
|
||||
else
|
||||
Twilio::REST::Client.new(permitted_params[:account_sid], permitted_params[:auth_token])
|
||||
end
|
||||
client = Twilio::REST::Client.new(permitted_params[:account_sid], permitted_params[:auth_token])
|
||||
client.messages.list(limit: 1)
|
||||
end
|
||||
|
||||
@@ -44,7 +40,6 @@ class Api::V1::Accounts::Channels::TwilioChannelsController < Api::V1::Accounts:
|
||||
@twilio_channel = Current.account.twilio_sms.create!(
|
||||
account_sid: permitted_params[:account_sid],
|
||||
auth_token: permitted_params[:auth_token],
|
||||
api_key_sid: permitted_params[:api_key_sid],
|
||||
messaging_service_sid: permitted_params[:messaging_service_sid].presence,
|
||||
phone_number: phone_number,
|
||||
medium: medium
|
||||
@@ -57,7 +52,7 @@ class Api::V1::Accounts::Channels::TwilioChannelsController < Api::V1::Accounts:
|
||||
|
||||
def permitted_params
|
||||
params.require(:twilio_channel).permit(
|
||||
:account_id, :messaging_service_sid, :phone_number, :account_sid, :auth_token, :name, :medium, :api_key_sid
|
||||
:account_id, :messaging_service_sid, :phone_number, :account_sid, :auth_token, :name, :medium
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -42,12 +42,6 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
|
||||
head :ok
|
||||
end
|
||||
|
||||
def export
|
||||
column_names = params['column_names']
|
||||
Account::ContactsExportJob.perform_later(Current.account.id, column_names)
|
||||
head :ok, message: I18n.t('errors.contacts.export.success')
|
||||
end
|
||||
|
||||
# returns online contacts
|
||||
def active
|
||||
contacts = Current.account.contacts.where(id: ::OnlineStatusTracker
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
class Api::V1::Accounts::Conversations::BaseController < Api::V1::Accounts::BaseController
|
||||
include EnsureCurrentAccountHelper
|
||||
before_action :conversation
|
||||
|
||||
private
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class Api::V1::Accounts::CustomFiltersController < Api::V1::Accounts::BaseController
|
||||
before_action :check_authorization
|
||||
before_action :fetch_custom_filters, except: [:create]
|
||||
before_action :fetch_custom_filter, only: [:show, :update, :destroy]
|
||||
DEFAULT_FILTER_TYPE = 'conversation'.freeze
|
||||
|
||||
@@ -63,7 +63,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
||||
end
|
||||
|
||||
def destroy
|
||||
::DeleteObjectJob.perform_later(@inbox, Current.user, request.ip) if @inbox.present?
|
||||
::DeleteObjectJob.perform_later(@inbox) 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, :sender_name_type, :business_name]
|
||||
:lock_to_single_conversation, :portal_id]
|
||||
end
|
||||
|
||||
def permitted_params(channel_attributes = [])
|
||||
|
||||
@@ -37,7 +37,6 @@ class Api::V1::AccountsController < Api::BaseController
|
||||
end
|
||||
|
||||
def cache_keys
|
||||
expires_in 10.seconds, public: false, stale_while_revalidate: 5.minutes
|
||||
render json: { cache_keys: get_cache_keys }, status: :ok
|
||||
end
|
||||
|
||||
|
||||
@@ -17,8 +17,7 @@ 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 },
|
||||
retain_original_contact_name: true
|
||||
params: { email: contact_email, name: contact_name }
|
||||
).perform
|
||||
else
|
||||
@message.update!(message_update_params[:message])
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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]
|
||||
@@ -15,7 +14,7 @@ class DashboardController < ActionController::Base
|
||||
|
||||
def set_global_config
|
||||
@global_config = GlobalConfig.get(
|
||||
'LOGO', 'LOGO_DARK', 'LOGO_THUMBNAIL',
|
||||
'LOGO', 'LOGO_THUMBNAIL',
|
||||
'INSTALLATION_NAME',
|
||||
'WIDGET_BRAND_URL', 'TERMS_URL',
|
||||
'PRIVACY_URL',
|
||||
@@ -61,12 +60,4 @@ 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
|
||||
|
||||
@@ -43,6 +43,8 @@ class Public::Api::V1::Portals::ArticlesController < Public::Api::V1::Portals::B
|
||||
end
|
||||
|
||||
def render_article_content(content)
|
||||
ChatwootMarkdownRenderer.new(content).render_article
|
||||
# rubocop:disable Rails/OutputSafety
|
||||
CommonMarker.render_html(content).html_safe
|
||||
# rubocop:enable Rails/OutputSafety
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,8 +6,6 @@ class Public::Api::V1::Portals::BaseController < PublicController
|
||||
def set_locale(&)
|
||||
switch_locale_with_portal(&) if params[:locale].present?
|
||||
switch_locale_with_article(&) if params[:article_slug].present?
|
||||
|
||||
yield
|
||||
end
|
||||
|
||||
def switch_locale_with_portal(&)
|
||||
|
||||
@@ -41,14 +41,4 @@ class SuperAdmin::AgentBotsController < SuperAdmin::ApplicationController
|
||||
|
||||
# See https://administrate-prototype.herokuapp.com/customizing_controller_actions
|
||||
# for more information
|
||||
|
||||
def destroy_avatar
|
||||
avatar = requested_resource.avatar
|
||||
avatar.purge
|
||||
redirect_back(fallback_location: super_admin_agent_bots_path)
|
||||
end
|
||||
|
||||
def scoped_resource
|
||||
resource_class.with_attached_avatar
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,17 +5,6 @@ class SuperAdmin::InstanceStatusesController < SuperAdmin::ApplicationController
|
||||
sha
|
||||
postgres_status
|
||||
redis_metrics
|
||||
chatwoot_edition
|
||||
end
|
||||
|
||||
def chatwoot_edition
|
||||
@metrics['Chatwoot edition'] = if ChatwootApp.enterprise?
|
||||
'Enterprise'
|
||||
elsif ChatwootApp.custom?
|
||||
'Custom'
|
||||
else
|
||||
'Community'
|
||||
end
|
||||
end
|
||||
|
||||
def chatwoot_version
|
||||
|
||||
@@ -45,17 +45,6 @@ class SuperAdmin::UsersController < SuperAdmin::ApplicationController
|
||||
# empty values into nil values. It uses other APIs such as `resource_class`
|
||||
# and `dashboard`:
|
||||
#
|
||||
|
||||
def destroy_avatar
|
||||
avatar = requested_resource.avatar
|
||||
avatar.purge
|
||||
redirect_back(fallback_location: super_admin_users_path)
|
||||
end
|
||||
|
||||
def scoped_resource
|
||||
resource_class.with_attached_avatar
|
||||
end
|
||||
|
||||
def resource_params
|
||||
permitted_params = super
|
||||
permitted_params.delete(:password) if permitted_params[:password].blank?
|
||||
|
||||
@@ -10,11 +10,6 @@ class AgentBotDashboard < Administrate::BaseDashboard
|
||||
ATTRIBUTE_TYPES = {
|
||||
access_token: Field::HasOne,
|
||||
avatar_url: AvatarField,
|
||||
avatar: Field::ActiveStorage.with_options(
|
||||
destroy_url: proc do |_namespace, _resource, attachment|
|
||||
[:avatar_super_admin_agent_bot, { attachment_id: attachment.id }]
|
||||
end
|
||||
),
|
||||
id: Field::Number,
|
||||
name: Field::String,
|
||||
account: Field::BelongsTo.with_options(searchable: true, searchable_field: 'name', order: 'id DESC'),
|
||||
@@ -41,7 +36,6 @@ class AgentBotDashboard < Administrate::BaseDashboard
|
||||
# an array of attributes that will be displayed on the model's show page.
|
||||
SHOW_PAGE_ATTRIBUTES = %i[
|
||||
id
|
||||
avatar_url
|
||||
account
|
||||
name
|
||||
description
|
||||
@@ -53,7 +47,6 @@ class AgentBotDashboard < Administrate::BaseDashboard
|
||||
# on the model's form (`new` and `edit`) pages.
|
||||
FORM_ATTRIBUTES = %i[
|
||||
name
|
||||
avatar
|
||||
account
|
||||
description
|
||||
outgoing_url
|
||||
|
||||
@@ -11,11 +11,6 @@ class UserDashboard < Administrate::BaseDashboard
|
||||
account_users: Field::HasMany,
|
||||
id: Field::Number,
|
||||
avatar_url: AvatarField,
|
||||
avatar: Field::ActiveStorage.with_options(
|
||||
destroy_url: proc do |_namespace, _resource, attachment|
|
||||
[:avatar_super_admin_user, { attachment_id: attachment.id }]
|
||||
end
|
||||
),
|
||||
provider: Field::String,
|
||||
uid: Field::String,
|
||||
password: Field::Password,
|
||||
@@ -74,7 +69,6 @@ class UserDashboard < Administrate::BaseDashboard
|
||||
# on the model's form (`new` and `edit`) pages.
|
||||
FORM_ATTRIBUTES = %i[
|
||||
name
|
||||
avatar
|
||||
display_name
|
||||
email
|
||||
password
|
||||
|
||||
@@ -6,8 +6,7 @@ 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_waiting_since: 'sort_on_waiting_since'
|
||||
sort_on_priority: 'sort_on_priority'
|
||||
}.with_indifferent_access
|
||||
|
||||
# assumptions
|
||||
@@ -103,7 +102,7 @@ class ConversationFinder
|
||||
when 'participating'
|
||||
@conversations = current_user.participating_conversations.where(account_id: current_account.id)
|
||||
when 'unattended'
|
||||
@conversations = @conversations.unattended
|
||||
@conversations = @conversations.where(first_reply_created_at: nil)
|
||||
end
|
||||
@conversations
|
||||
end
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
module BillingHelper
|
||||
private
|
||||
|
||||
def default_plan?(account)
|
||||
installation_config = InstallationConfig.find_by(name: 'CHATWOOT_CLOUD_PLANS')
|
||||
default_plan = installation_config&.value&.first
|
||||
|
||||
# Return false if not plans are configured, so that no checks are enforced
|
||||
return false if default_plan.blank?
|
||||
|
||||
account.custom_attributes['plan_name'].nil? || account.custom_attributes['plan_name'] == default_plan['name']
|
||||
end
|
||||
|
||||
def conversations_this_month(account)
|
||||
account.conversations.where('created_at > ?', 30.days.ago).count
|
||||
end
|
||||
|
||||
def non_web_inboxes(account)
|
||||
account.inboxes.where.not(channel_type: Channel::WebWidget.to_s).count
|
||||
end
|
||||
end
|
||||
@@ -7,6 +7,8 @@ module MessageFormatHelper
|
||||
end
|
||||
|
||||
def render_message_content(message_content)
|
||||
ChatwootMarkdownRenderer.new(message_content).render_message
|
||||
# rubocop:disable Rails/OutputSafety
|
||||
CommonMarker.render_html(message_content).html_safe
|
||||
# rubocop:enable Rails/OutputSafety
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,36 +17,19 @@ module ReportHelper
|
||||
end
|
||||
|
||||
def conversations_count
|
||||
(get_grouped_values conversations).count
|
||||
(get_grouped_values scope.conversations.where(account_id: account.id)).count
|
||||
end
|
||||
|
||||
def incoming_messages_count
|
||||
(get_grouped_values incoming_messages).count
|
||||
(get_grouped_values scope.messages.where(account_id: account.id).incoming.unscope(:order)).count
|
||||
end
|
||||
|
||||
def outgoing_messages_count
|
||||
(get_grouped_values outgoing_messages).count
|
||||
(get_grouped_values scope.messages.where(account_id: account.id).outgoing.unscope(:order)).count
|
||||
end
|
||||
|
||||
def resolutions_count
|
||||
(get_grouped_values resolutions).count
|
||||
end
|
||||
|
||||
def conversations
|
||||
scope.conversations.where(account_id: account.id, created_at: range)
|
||||
end
|
||||
|
||||
def incoming_messages
|
||||
scope.messages.where(account_id: account.id, created_at: range).incoming.unscope(:order)
|
||||
end
|
||||
|
||||
def outgoing_messages
|
||||
scope.messages.where(account_id: account.id, created_at: range).outgoing.unscope(:order)
|
||||
end
|
||||
|
||||
def resolutions
|
||||
scope.reporting_events.joins(:conversation).select(:conversation_id).where(account_id: account.id, name: :conversation_resolved,
|
||||
conversations: { status: :resolved }, created_at: range).distinct
|
||||
(get_grouped_values scope.conversations.where(account_id: account.id).resolved).count
|
||||
end
|
||||
|
||||
def avg_first_response_time
|
||||
@@ -56,13 +39,6 @@ module ReportHelper
|
||||
grouped_reporting_events.average(:value)
|
||||
end
|
||||
|
||||
def reply_time
|
||||
grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'reply_time', account_id: account.id))
|
||||
return grouped_reporting_events.average(:value_in_business_hours) if params[:business_hours]
|
||||
|
||||
grouped_reporting_events.average(:value)
|
||||
end
|
||||
|
||||
def avg_resolution_time
|
||||
grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'conversation_resolved', account_id: account.id))
|
||||
return grouped_reporting_events.average(:value_in_business_hours) if params[:business_hours]
|
||||
@@ -73,35 +49,17 @@ module ReportHelper
|
||||
def avg_resolution_time_summary
|
||||
reporting_events = scope.reporting_events
|
||||
.where(name: 'conversation_resolved', account_id: account.id, created_at: range)
|
||||
avg_rt = if params[:business_hours].present?
|
||||
reporting_events.average(:value_in_business_hours)
|
||||
else
|
||||
reporting_events.average(:value)
|
||||
end
|
||||
avg_rt = params[:business_hours] ? reporting_events.average(:value_in_business_hours) : reporting_events.average(:value)
|
||||
|
||||
return 0 if avg_rt.blank?
|
||||
|
||||
avg_rt
|
||||
end
|
||||
|
||||
def reply_time_summary
|
||||
reporting_events = scope.reporting_events
|
||||
.where(name: 'reply_time', account_id: account.id, created_at: range)
|
||||
reply_time = params[:business_hours] ? reporting_events.average(:value_in_business_hours) : reporting_events.average(:value)
|
||||
|
||||
return 0 if reply_time.blank?
|
||||
|
||||
reply_time
|
||||
end
|
||||
|
||||
def avg_first_response_time_summary
|
||||
reporting_events = scope.reporting_events
|
||||
.where(name: 'first_response', account_id: account.id, created_at: range)
|
||||
avg_frt = if params[:business_hours].present?
|
||||
reporting_events.average(:value_in_business_hours)
|
||||
else
|
||||
reporting_events.average(:value)
|
||||
end
|
||||
avg_frt = params[:business_hours] ? reporting_events.average(:value_in_business_hours) : reporting_events.average(:value)
|
||||
|
||||
return 0 if avg_frt.blank?
|
||||
|
||||
|
||||
@@ -3,14 +3,9 @@
|
||||
v-if="!authUIFlags.isFetching"
|
||||
id="app"
|
||||
class="app-wrapper app-root"
|
||||
:class="{ 'app-rtl--wrapper': isRTLView, dark: theme === 'dark' }"
|
||||
:dir="isRTLView ? 'rtl' : 'ltr'"
|
||||
:class="{ 'app-rtl--wrapper': isRTLView }"
|
||||
>
|
||||
<update-banner :latest-chatwoot-version="latestChatwootVersion" />
|
||||
<template v-if="!accountUIFlags.isFetchingItem && currentAccountId">
|
||||
<payment-pending-banner />
|
||||
<upgrade-banner />
|
||||
</template>
|
||||
<transition name="fade" mode="out-in">
|
||||
<router-view />
|
||||
</transition>
|
||||
@@ -30,17 +25,13 @@ import AddAccountModal from '../dashboard/components/layout/sidebarComponents/Ad
|
||||
import LoadingState from './components/widgets/LoadingState.vue';
|
||||
import NetworkNotification from './components/NetworkNotification';
|
||||
import UpdateBanner from './components/app/UpdateBanner.vue';
|
||||
import UpgradeBanner from './components/app/UpgradeBanner.vue';
|
||||
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',
|
||||
@@ -50,9 +41,7 @@ export default {
|
||||
LoadingState,
|
||||
NetworkNotification,
|
||||
UpdateBanner,
|
||||
PaymentPendingBanner,
|
||||
WootSnackbarBox,
|
||||
UpgradeBanner,
|
||||
},
|
||||
|
||||
mixins: [rtlMixin],
|
||||
@@ -61,7 +50,6 @@ export default {
|
||||
return {
|
||||
showAddAccountModal: false,
|
||||
latestChatwootVersion: null,
|
||||
theme: 'light',
|
||||
};
|
||||
},
|
||||
|
||||
@@ -71,7 +59,6 @@ export default {
|
||||
currentUser: 'getCurrentUser',
|
||||
globalConfig: 'globalConfig/get',
|
||||
authUIFlags: 'getAuthUIFlags',
|
||||
accountUIFlags: 'accounts/getUIFlags',
|
||||
currentAccountId: 'getCurrentAccountId',
|
||||
}),
|
||||
hasAccounts() {
|
||||
@@ -93,34 +80,9 @@ 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;
|
||||
},
|
||||
@@ -153,6 +115,11 @@ export default {
|
||||
|
||||
<style lang="scss">
|
||||
@import './assets/scss/app';
|
||||
.update-banner {
|
||||
height: var(--space-larger);
|
||||
align-items: center;
|
||||
font-size: var(--font-size-small) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
|
||||
|
||||
@@ -18,10 +18,6 @@ class CacheEnabledApiClient extends ApiClient {
|
||||
return this.getFromCache();
|
||||
}
|
||||
|
||||
return this.getFromNetwork();
|
||||
}
|
||||
|
||||
getFromNetwork() {
|
||||
return axios.get(this.url);
|
||||
}
|
||||
|
||||
@@ -36,12 +32,7 @@ class CacheEnabledApiClient extends ApiClient {
|
||||
}
|
||||
|
||||
async getFromCache() {
|
||||
try {
|
||||
// IDB is not supported in Firefox private mode: https://bugzilla.mozilla.org/show_bug.cgi?id=781982
|
||||
await this.dataManager.initDb();
|
||||
} catch {
|
||||
return this.getFromNetwork();
|
||||
}
|
||||
await this.dataManager.initDb();
|
||||
|
||||
const { data } = await axios.get(
|
||||
`/api/v1/accounts/${this.accountIdFromRoute}/cache_keys`
|
||||
@@ -64,22 +55,16 @@ class CacheEnabledApiClient extends ApiClient {
|
||||
}
|
||||
|
||||
async refetchAndCommit(newKey = null) {
|
||||
const response = await this.getFromNetwork();
|
||||
await this.dataManager.initDb();
|
||||
const response = await axios.get(this.url);
|
||||
this.dataManager.replace({
|
||||
modelName: this.cacheModelName,
|
||||
data: this.extractDataFromResponse(response),
|
||||
});
|
||||
|
||||
try {
|
||||
await this.dataManager.initDb();
|
||||
|
||||
this.dataManager.replace({
|
||||
modelName: this.cacheModelName,
|
||||
data: this.extractDataFromResponse(response),
|
||||
});
|
||||
|
||||
await this.dataManager.setCacheKeys({
|
||||
[this.cacheModelName]: newKey,
|
||||
});
|
||||
} catch {
|
||||
// Ignore error
|
||||
}
|
||||
await this.dataManager.setCacheKeys({
|
||||
[this.cacheModelName]: newKey,
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -3,11 +3,47 @@
|
||||
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);
|
||||
@@ -37,6 +73,45 @@ 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,
|
||||
|
||||
@@ -75,10 +75,6 @@ class ContactAPI extends ApiClient {
|
||||
destroyAvatar(contactId) {
|
||||
return axios.delete(`${this.url}/${contactId}/avatar`);
|
||||
}
|
||||
|
||||
exportContacts() {
|
||||
return axios.get(`${this.url}/export`);
|
||||
}
|
||||
}
|
||||
|
||||
export default new ContactAPI();
|
||||
|
||||
@@ -13,10 +13,6 @@ class EnterpriseAccountAPI extends ApiClient {
|
||||
subscription() {
|
||||
return axios.post(`${this.url}subscription`);
|
||||
}
|
||||
|
||||
getLimits() {
|
||||
return axios.get(`${this.url}limits`);
|
||||
}
|
||||
}
|
||||
|
||||
export default new EnterpriseAccountAPI();
|
||||
|
||||
@@ -127,10 +127,6 @@ class ConversationApi extends ApiClient {
|
||||
user_ids: userIds,
|
||||
});
|
||||
}
|
||||
|
||||
getAllAttachments(conversationId) {
|
||||
return axios.get(`${this.url}/${conversationId}/attachments`);
|
||||
}
|
||||
}
|
||||
|
||||
export default new ConversationApi();
|
||||
|
||||
@@ -10,7 +10,6 @@ export const buildCreatePayload = ({
|
||||
files,
|
||||
ccEmails = '',
|
||||
bccEmails = '',
|
||||
toEmails = '',
|
||||
templateParams,
|
||||
}) => {
|
||||
let payload;
|
||||
@@ -26,9 +25,6 @@ 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,
|
||||
@@ -37,7 +33,6 @@ export const buildCreatePayload = ({
|
||||
content_attributes: contentAttributes,
|
||||
cc_emails: ccEmails,
|
||||
bcc_emails: bccEmails,
|
||||
to_emails: toEmails,
|
||||
template_params: templateParams,
|
||||
};
|
||||
}
|
||||
@@ -58,7 +53,6 @@ class MessageApi extends ApiClient {
|
||||
files,
|
||||
ccEmails = '',
|
||||
bccEmails = '',
|
||||
toEmails = '',
|
||||
templateParams,
|
||||
}) {
|
||||
return axios({
|
||||
@@ -72,7 +66,6 @@ class MessageApi extends ApiClient {
|
||||
files,
|
||||
ccEmails,
|
||||
bccEmails,
|
||||
toEmails,
|
||||
templateParams,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -2,62 +2,18 @@
|
||||
|
||||
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 (this.conversation_events.includes(type)) {
|
||||
if (type === 'reply_suggestion' || type === 'summarize') {
|
||||
data = {
|
||||
conversation_display_id: conversationId,
|
||||
};
|
||||
|
||||
@@ -210,12 +210,5 @@ describe('#ConversationAPI', () => {
|
||||
{ params: { page: payload.page } }
|
||||
);
|
||||
});
|
||||
|
||||
it('#getAllAttachments', () => {
|
||||
conversationAPI.getAllAttachments(1);
|
||||
expect(context.axiosMock.get).toHaveBeenCalledWith(
|
||||
'/api/v1/conversations/1/attachments'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/* global axios */
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
import wootAPI from './apiClient';
|
||||
|
||||
export const getTestimonialContent = () => {
|
||||
return wootAPI.get(wootConstants.TESTIMONIAL_URL);
|
||||
return axios.get(wootConstants.TESTIMONIAL_URL);
|
||||
};
|
||||
@@ -1,64 +1,37 @@
|
||||
@import '~vue2-datepicker/scss/index';
|
||||
|
||||
.mx-datepicker-popup {
|
||||
@apply z-[99999];
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
.date-picker {
|
||||
&.no-margin {
|
||||
.mx-input {
|
||||
@apply mb-0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.auto-width) {
|
||||
.mx-datepicker-range {
|
||||
@apply w-[320px];
|
||||
width: 320px;
|
||||
}
|
||||
}
|
||||
|
||||
.mx-datepicker {
|
||||
@apply w-full;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mx-input {
|
||||
@apply h-[2.5rem] flex border border-solid border-slate-200 dark:border-slate-600 rounded-md shadow-none;
|
||||
border: 1px solid var(--s-200);
|
||||
border-radius: var(--border-radius-normal);
|
||||
box-shadow: none;
|
||||
display: flex;
|
||||
height: 4.0rem;
|
||||
}
|
||||
|
||||
.mx-input:disabled,
|
||||
.mx-input[readonly] {
|
||||
@apply bg-white dark:bg-slate-900 cursor-pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.mx-calendar-content .cell:hover {
|
||||
@apply bg-slate-75 dark:bg-slate-700 text-slate-900 dark:text-slate-100;
|
||||
}
|
||||
|
||||
.mx-datepicker-inline {
|
||||
@apply w-full;
|
||||
|
||||
.mx-calendar {
|
||||
@apply w-full;
|
||||
}
|
||||
|
||||
.cell.disabled {
|
||||
@apply bg-slate-25 dark:bg-slate-900 text-slate-200 dark:text-slate-300;
|
||||
}
|
||||
|
||||
.mx-time-item.disabled {
|
||||
@apply bg-slate-25 dark:bg-slate-900;
|
||||
}
|
||||
|
||||
.today {
|
||||
@apply font-semibold;
|
||||
}
|
||||
|
||||
.mx-datepicker-main {
|
||||
@apply border-0 bg-white dark:bg-slate-800;
|
||||
}
|
||||
|
||||
.mx-time-header {
|
||||
@apply border-0;
|
||||
background-color: var(--white);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
}
|
||||
|
||||
select {
|
||||
height: 2.5rem;
|
||||
height: 4.0rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
@@ -16,6 +16,19 @@ select {
|
||||
padding: var(--space-normal);
|
||||
}
|
||||
|
||||
.button-wrapper .button.grey-btn {
|
||||
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: 16px;
|
||||
$global-font-size: 10px;
|
||||
$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: 'PlusJakarta',
|
||||
$body-font-family: 'Inter',
|
||||
-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.3125rem;
|
||||
$header-margin-bottom: 0.5rem;
|
||||
$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.65;
|
||||
$paragraph-lineheight: 1.45;
|
||||
$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: 0.78125rem;
|
||||
$list-nested-side-margin: 0.78125rem;
|
||||
$defnlist-margin-bottom: 0.6875rem;
|
||||
$list-side-margin: 1.25rem;
|
||||
$list-nested-side-margin: 1.25rem;
|
||||
$defnlist-margin-bottom: 1rem;
|
||||
$defnlist-term-weight: $global-weight-bold;
|
||||
$defnlist-term-margin-bottom: 0.1875rem;
|
||||
$defnlist-term-margin-bottom: 0.3rem;
|
||||
$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.125rem;
|
||||
$subheader-margin-bottom: 0.3125rem;
|
||||
$stat-font-size: 1.5625rem;
|
||||
$subheader-margin-top: 0.2rem;
|
||||
$subheader-margin-bottom: 0.5rem;
|
||||
$stat-font-size: 2.5rem;
|
||||
|
||||
// 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: 0.78125rem 0.625rem;
|
||||
$accordion-item-padding: 1.25rem 1rem;
|
||||
$accordion-content-background: $white;
|
||||
$accordion-content-border: 1px solid $light-gray;
|
||||
$accordion-content-color: $body-font-color;
|
||||
$accordion-content-padding: 0.625rem;
|
||||
$accordion-content-padding: 1rem;
|
||||
|
||||
// 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.46875rem;
|
||||
$breadcrumbs-item-margin: 0.75rem;
|
||||
$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 0.625rem 0;
|
||||
$callout-padding: 0.625rem;
|
||||
$callout-margin: 0 0 1rem 0;
|
||||
$callout-padding: 1rem;
|
||||
$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: 0.625rem;
|
||||
$dropdown-padding: 1rem;
|
||||
$dropdown-background: $body-background;
|
||||
$dropdown-border: 1px solid $medium-gray;
|
||||
$dropdown-font-size: 0.625rem;
|
||||
$dropdown-font-size: 1rem;
|
||||
$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: 0.625rem;
|
||||
$input-prefix-padding: 1rem;
|
||||
$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.15625rem;
|
||||
$menu-icon-spacing: 0.25rem;
|
||||
$menu-item-background-hover: $light-gray;
|
||||
$menu-border: $light-gray;
|
||||
|
||||
// 23. Meter
|
||||
// ---------
|
||||
|
||||
$meter-height: 0.625rem;
|
||||
$meter-height: 1rem;
|
||||
$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: 14.375,
|
||||
medium: 14.375,
|
||||
$offcanvas-sizes: (small: 23rem,
|
||||
medium: 23rem,
|
||||
);
|
||||
$offcanvas-vertical-sizes: (small: 14.375,
|
||||
medium: 14.375,
|
||||
$offcanvas-vertical-sizes: (small: 23rem,
|
||||
medium: 23rem,
|
||||
);
|
||||
$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: 0.75rem;
|
||||
$orbit-bullet-margin: 0.0625rem;
|
||||
$orbit-bullet-margin-top: 0.5rem;
|
||||
$orbit-bullet-margin-bottom: 0.5rem;
|
||||
$orbit-bullet-diameter: 1.2rem;
|
||||
$orbit-bullet-margin: 0.1rem;
|
||||
$orbit-bullet-margin-top: 0.8rem;
|
||||
$orbit-bullet-margin-bottom: 0.8rem;
|
||||
$orbit-caption-background: rgba($black, 0.5);
|
||||
$orbit-caption-padding: 0.625rem;
|
||||
$orbit-caption-padding: 1rem;
|
||||
$orbit-control-background-hover: rgba($black, 0.5);
|
||||
$orbit-control-padding: 0.625rem;
|
||||
$orbit-control-padding: 1rem;
|
||||
$orbit-control-zindex: 10;
|
||||
|
||||
// 26. Pagination
|
||||
@@ -476,7 +476,7 @@ $pagination-arrows: true;
|
||||
// 27. Progress Bar
|
||||
// ----------------
|
||||
|
||||
$progress-height: 0.625rem;
|
||||
$progress-height: 1rem;
|
||||
$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.3125rem;
|
||||
$slider-width-vertical: 0.5rem;
|
||||
$slider-transition: all 0.2s ease-in-out;
|
||||
$slider-height: 0.3125rem;
|
||||
$slider-height: 0.5rem;
|
||||
$slider-background: $light-gray;
|
||||
$slider-fill-background: $medium-gray;
|
||||
$slider-handle-height: 0.875rem;
|
||||
$slider-handle-width: 0.875rem;
|
||||
$slider-handle-height: 1.4rem;
|
||||
$slider-handle-width: 1.4rem;
|
||||
$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: 0.625rem;
|
||||
$tab-content-padding: 1rem;
|
||||
|
||||
// 34. Thumbnail
|
||||
// -------------
|
||||
@@ -586,11 +586,11 @@ $thumbnail-radius: $global-radius;
|
||||
|
||||
$titlebar-background: $black;
|
||||
$titlebar-color: $white;
|
||||
$titlebar-padding: 0.3125rem;
|
||||
$titlebar-padding: 0.5rem;
|
||||
$titlebar-text-font-weight: bold;
|
||||
$titlebar-icon-color: $white;
|
||||
$titlebar-icon-color-hover: $medium-gray;
|
||||
$titlebar-icon-spacing: 0.15625rem;
|
||||
$titlebar-icon-spacing: 0.25rem;
|
||||
|
||||
// 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.46875rem;
|
||||
$tooltip-padding: 0.75rem;
|
||||
$tooltip-font-size: $font-size-mini;
|
||||
$tooltip-pip-width: 0.46875rem;
|
||||
$tooltip-pip-width: 0.75rem;
|
||||
$tooltip-pip-height: $tooltip-pip-width * 0.866;
|
||||
$tooltip-radius: $global-radius;
|
||||
|
||||
// 37. Top Bar
|
||||
// -----------
|
||||
|
||||
$topbar-padding: 0.3125;
|
||||
$topbar-padding: 0.5rem;
|
||||
$topbar-background: $light-gray;
|
||||
$topbar-submenu-background: $topbar-background;
|
||||
$topbar-title-spacing: 0.3125 0.625rem 0.3125 0;
|
||||
$topbar-title-spacing: 0.5rem 1rem 0.5rem 0;
|
||||
$topbar-input-width: 200px;
|
||||
$topbar-unstack-breakpoint: medium;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.bg-light {
|
||||
@apply bg-slate-25 dark:bg-slate-800;
|
||||
@include background-light;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
|
||||
@@ -22,43 +22,43 @@ $spinner-before-border-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
@mixin border-normal() {
|
||||
@apply border border-slate-50 dark:border-slate-700;
|
||||
border: 1px solid $color-border;
|
||||
}
|
||||
|
||||
@mixin border-normal-left() {
|
||||
@apply border-l border-slate-50 dark:border-slate-700;
|
||||
border-left: 1px solid $color-border;
|
||||
}
|
||||
|
||||
@mixin border-normal-top() {
|
||||
@apply border-t border-slate-50 dark:border-slate-700;
|
||||
border-top: 1px solid $color-border;
|
||||
}
|
||||
|
||||
@mixin border-normal-right() {
|
||||
@apply border-r border-slate-50 dark:border-slate-700;
|
||||
border-right: 1px solid $color-border;
|
||||
}
|
||||
|
||||
@mixin border-normal-bottom() {
|
||||
@apply border-b border-slate-50 dark:border-slate-700;
|
||||
border-bottom: 1px solid $color-border;
|
||||
}
|
||||
|
||||
@mixin border-light() {
|
||||
@apply border border-slate-25 dark:border-slate-700;
|
||||
border: 1px solid $color-border-light;
|
||||
}
|
||||
|
||||
@mixin border-light-left() {
|
||||
@apply border-l border-slate-25 dark:border-slate-700;
|
||||
border-left: 1px solid $color-border-light;
|
||||
}
|
||||
|
||||
@mixin border-light-top() {
|
||||
@apply border-t border-slate-25 dark:border-slate-700;
|
||||
border-top: 1px solid $color-border-light;
|
||||
}
|
||||
|
||||
@mixin border-light-right() {
|
||||
@apply border-r border-slate-25 dark:border-slate-700;
|
||||
border-right: 1px solid $color-border-light;
|
||||
}
|
||||
|
||||
@mixin border-light-bottom() {
|
||||
@apply border-b border-slate-25 dark:border-slate-700;
|
||||
border-bottom: 1px solid $color-border-light;
|
||||
}
|
||||
|
||||
// background
|
||||
@@ -67,11 +67,11 @@ $spinner-before-border-color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
@mixin background-light() {
|
||||
@apply bg-slate-50 dark:bg-slate-800;
|
||||
background: $color-background-light;
|
||||
}
|
||||
|
||||
@mixin background-white() {
|
||||
@apply bg-white dark:bg-slate-900;
|
||||
background: $color-white;
|
||||
}
|
||||
|
||||
// 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: 16rem,
|
||||
$column-three-width: 16rem) {
|
||||
@mixin three-column-grid($column-one-width: 25.6rem,
|
||||
$column-three-width: 25.6rem) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: grid;
|
||||
|
||||
@@ -1,6 +1,90 @@
|
||||
.app-rtl--wrapper {
|
||||
direction: rtl;
|
||||
|
||||
// Primary sidebar
|
||||
.primary--sidebar {
|
||||
border-left: 1px solid var(--s-50);
|
||||
border-right: 0;
|
||||
|
||||
.options-menu.dropdown-pane {
|
||||
right: var(--space-smaller);
|
||||
|
||||
.auto-offline--toggle {
|
||||
padding: var(--space-smaller) var(--space-one) var(--space-smaller)
|
||||
var(--space-smaller);
|
||||
}
|
||||
|
||||
.status-items .button {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
margin-left: var(--space-small);
|
||||
margin-right: var(--space-smaller);
|
||||
}
|
||||
}
|
||||
|
||||
.header-section.back-button {
|
||||
direction: initial;
|
||||
margin-left: var(--space-normal);
|
||||
@@ -49,6 +133,23 @@
|
||||
|
||||
// Conversation details
|
||||
.conversation-details-wrap {
|
||||
.conv-header {
|
||||
.user {
|
||||
margin-left: var(--space-normal);
|
||||
margin-right: unset;
|
||||
|
||||
.user--profile__meta {
|
||||
margin-left: unset;
|
||||
margin-right: var(--space-small);
|
||||
}
|
||||
}
|
||||
|
||||
.actions--container .resolve-actions {
|
||||
margin-left: unset;
|
||||
margin-right: var(--space-small);
|
||||
}
|
||||
}
|
||||
|
||||
.conversation-panel {
|
||||
// Message text
|
||||
.text-content {
|
||||
@@ -96,6 +197,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Conversation sidebar toggle button
|
||||
.sidebar-toggle--button {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
// Conversation sidebar close button
|
||||
.close-button--rtl {
|
||||
transform: rotate(180deg);
|
||||
@@ -239,6 +345,31 @@
|
||||
}
|
||||
}
|
||||
|
||||
// scss-lint:disable SelectorDepth
|
||||
.container .header-wrap .header-left-wrap .header-left-wrap > .page-title {
|
||||
margin-right: var(--space-small);
|
||||
}
|
||||
|
||||
.portal-container .container {
|
||||
margin-left: unset !important;
|
||||
margin-right: var(--space-small);
|
||||
|
||||
.configuration-items--wrap {
|
||||
margin-left: var(--space-mega);
|
||||
margin-right: unset !important;
|
||||
}
|
||||
|
||||
thead th {
|
||||
padding-left: var(--space-small);
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
tbody td {
|
||||
padding-left: var(--space-small);
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.portal-popover__container .portal {
|
||||
.actions-container {
|
||||
margin-left: unset;
|
||||
@@ -308,7 +439,7 @@
|
||||
}
|
||||
|
||||
span {
|
||||
--minus-space-one-point-five: -0.9375rem;
|
||||
--minus-space-one-point-five: -1.5rem;
|
||||
|
||||
&.active {
|
||||
transform: translate(
|
||||
@@ -342,6 +473,11 @@
|
||||
direction: initial;
|
||||
}
|
||||
|
||||
.inbox--name .inbox--icon {
|
||||
margin-left: var(--space-micro);
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.colorpicker--chrome {
|
||||
direction: initial;
|
||||
}
|
||||
|
||||
@@ -29,5 +29,4 @@ a {
|
||||
|
||||
p {
|
||||
font-size: $font-size-small;
|
||||
word-spacing: .12em;
|
||||
}
|
||||
|
||||
@@ -43,13 +43,17 @@
|
||||
}
|
||||
|
||||
.border-right {
|
||||
@apply border-r border-slate-50 dark:border-slate-700;
|
||||
border-right: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.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.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;
|
||||
$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;
|
||||
|
||||
// spaces
|
||||
$zero: 0;
|
||||
$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;
|
||||
$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;
|
||||
|
||||
// font-weight
|
||||
$font-weight-feather: 100;
|
||||
@@ -35,8 +35,8 @@ $font-weight-bold: 600;
|
||||
$font-weight-black: 700;
|
||||
|
||||
//Navbar
|
||||
$nav-bar-width: 14.375rem;
|
||||
$header-height: 3.5rem;
|
||||
$nav-bar-width: 23rem;
|
||||
$header-height: 5.6rem;
|
||||
|
||||
$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: 2.5rem;
|
||||
$thumbnail-radius: 4rem;
|
||||
|
||||
// chat-header
|
||||
$conv-header-height: 2.5rem;
|
||||
$conv-header-height: 4rem;
|
||||
|
||||
// Inbox List
|
||||
|
||||
$inbox-thumb-size: 3rem;
|
||||
$inbox-thumb-size: 4.8rem;
|
||||
|
||||
|
||||
// Spinner
|
||||
$spinkit-spinner-color: $color-white !default;
|
||||
$spinkit-spinner-margin: 0 0 0 1rem !default;
|
||||
$spinkit-size: 1rem !default;
|
||||
$spinkit-spinner-margin: 0 0 0 1.6rem !default;
|
||||
$spinkit-size: 1.6rem !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: 2.4375rem;
|
||||
--dashboard-app-tabs-height: 3.9rem;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
@import 'tailwindcss/base';
|
||||
@import 'tailwindcss/components';
|
||||
@import 'tailwindcss/utilities';
|
||||
|
||||
@import 'shared/assets/fonts/plus-jakarta';
|
||||
@import 'shared/assets/fonts/inter';
|
||||
@import 'shared/assets/stylesheets/animations';
|
||||
@import 'shared/assets/stylesheets/colors';
|
||||
@import 'shared/assets/stylesheets/spacing';
|
||||
@@ -71,8 +67,3 @@
|
||||
@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;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
z-index: var(--z-index-very-high);
|
||||
|
||||
&.dropdown-pane--open {
|
||||
@apply bg-white dark:bg-slate-800;
|
||||
display: block;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
@@ -1,86 +1,93 @@
|
||||
@mixin label-multiselect-hover {
|
||||
&::after {
|
||||
@apply text-woot-600 dark:text-woot-600;
|
||||
color: $color-primary-dark;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@apply bg-slate-50 dark:bg-slate-700;
|
||||
background: $color-background;
|
||||
|
||||
&::after {
|
||||
@apply text-woot-500 dark:text-woot-500;
|
||||
color: $color-woot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.multiselect {
|
||||
&:not(.no-margin) {
|
||||
@apply mb-4;
|
||||
margin-bottom: var(--space-normal);
|
||||
}
|
||||
|
||||
&.multiselect--disabled {
|
||||
@apply opacity-80;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.multiselect--active {
|
||||
> .multiselect__tags {
|
||||
@apply border-woot-500 dark:border-woot-500;
|
||||
>.multiselect__tags {
|
||||
border-color: var(--w-500);
|
||||
}
|
||||
}
|
||||
|
||||
.multiselect__select {
|
||||
@apply min-h-[2.875rem] p-0 right-0 top-0;
|
||||
min-height: 4.6rem;
|
||||
padding: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
||||
&::before {
|
||||
@apply right-0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.multiselect__content-wrapper {
|
||||
@apply bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-600 text-slate-800 dark:text-slate-100;
|
||||
}
|
||||
|
||||
.multiselect__content {
|
||||
@apply max-w-full;
|
||||
max-width: 100%;
|
||||
|
||||
.multiselect__option {
|
||||
@apply text-sm font-normal;
|
||||
font-size: $font-size-small;
|
||||
font-weight: $font-weight-normal;
|
||||
|
||||
span {
|
||||
@apply inline-block overflow-hidden text-ellipsis whitespace-nowrap w-fit;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply mb-0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.multiselect__option--highlight {
|
||||
@apply bg-white dark:bg-slate-800 text-slate-800 dark:text-slate-100;
|
||||
background: var(--white);
|
||||
color: var(--color-body);
|
||||
}
|
||||
|
||||
&.multiselect__option--highlight:hover {
|
||||
@apply bg-woot-50 dark:bg-woot-600 text-slate-800 dark:text-slate-100;
|
||||
background: var(--w-50);
|
||||
color: var(--color-body);
|
||||
|
||||
&::after {
|
||||
@apply bg-woot-50 dark:bg-woot-600 text-slate-600 dark:text-slate-200;
|
||||
background: var(--w-50);
|
||||
color: var(--s-600);
|
||||
}
|
||||
}
|
||||
|
||||
&.multiselect__option--highlight::after {
|
||||
@apply bg-transparent;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&.multiselect__option--selected {
|
||||
@apply bg-woot-50 dark:bg-woot-600 text-slate-800 dark:text-slate-100;
|
||||
background: var(--w-75);
|
||||
|
||||
&.multiselect__option--highlight:hover {
|
||||
@apply bg-woot-75 dark:bg-woot-600;
|
||||
background: var(--w-75);
|
||||
|
||||
&::after {
|
||||
@apply bg-transparent;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::after:hover {
|
||||
@apply text-slate-800 dark:text-slate-100;
|
||||
color: var(--color-body);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,130 +95,175 @@
|
||||
}
|
||||
|
||||
.multiselect__tags {
|
||||
@apply bg-white dark:bg-slate-900 border border-solid border-slate-200 dark:border-slate-600 m-0 min-h-[2.875rem] pt-0;
|
||||
border: 1px solid var(--s-200);
|
||||
border-color: var(--s-200);
|
||||
margin: 0;
|
||||
min-height: 4.4rem;
|
||||
padding-top: $zero;
|
||||
}
|
||||
|
||||
.multiselect__tags-wrap {
|
||||
@apply inline-block leading-none mt-1;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
margin-top: $space-smaller;
|
||||
}
|
||||
|
||||
.multiselect__placeholder {
|
||||
@apply text-slate-400 dark:text-slate-400 font-normal pt-3;
|
||||
color: $color-gray;
|
||||
font-weight: $font-weight-normal;
|
||||
padding-top: var(--space-slab);
|
||||
}
|
||||
|
||||
.multiselect__tag {
|
||||
@apply bg-slate-50 dark:bg-slate-800 mt-1 text-slate-800 dark:text-slate-100 pr-6 pl-2.5 py-1.5;
|
||||
$vertical-space: $space-smaller + $space-micro;
|
||||
background: $color-background;
|
||||
color: $color-heading;
|
||||
margin-top: $space-smaller;
|
||||
padding: $vertical-space $space-medium $vertical-space $space-one;
|
||||
}
|
||||
|
||||
.multiselect__tag-icon {
|
||||
@include label-multiselect-hover;
|
||||
line-height: $space-medium + $space-micro;
|
||||
}
|
||||
|
||||
.multiselect__input {
|
||||
@include ghost-input;
|
||||
@apply text-sm h-[2.875rem] mb-0 p-0;
|
||||
font-size: $font-size-small;
|
||||
height: 4.4rem;
|
||||
margin-bottom: $zero;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.multiselect__single {
|
||||
@apply bg-white dark:bg-slate-900 text-slate-800 dark:text-slate-100 inline-block mb-0 py-3 px-2.5 overflow-hidden whitespace-nowrap text-ellipsis;
|
||||
@include text-ellipsis;
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
padding: var(--space-slab) var(--space-one);
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-labels-wrap {
|
||||
|
||||
&.has-edited,
|
||||
&:hover {
|
||||
.multiselect {
|
||||
@apply cursor-pointer;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.multiselect {
|
||||
> .multiselect__select {
|
||||
@apply invisible;
|
||||
>.multiselect__select {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
> .multiselect__tags {
|
||||
@apply border-transparent;
|
||||
>.multiselect__tags {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
&.multiselect--active > .multiselect__tags {
|
||||
@apply border-woot-500 dark:border-woot-500;
|
||||
&.multiselect--active>.multiselect__tags {
|
||||
border-color: $color-woot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.multiselect-wrap--small {
|
||||
$multiselect-height: 4.0rem;
|
||||
|
||||
.multiselect__tags,
|
||||
.multiselect__input {
|
||||
@apply items-center flex;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.multiselect__tags,
|
||||
.multiselect__input,
|
||||
.multiselect {
|
||||
@apply bg-white dark:bg-slate-900 text-slate-800 dark:text-slate-100 rounded-[5px] text-sm h-10 min-h-[2.5rem];
|
||||
background: var(--white);
|
||||
font-size: var(--font-size-small);
|
||||
height: $multiselect-height;
|
||||
min-height: $multiselect-height;
|
||||
}
|
||||
|
||||
.multiselect__input {
|
||||
@apply h-[2.375rem] min-h-[2.375rem];
|
||||
height: $multiselect-height - $space-micro;
|
||||
min-height: $multiselect-height - $space-micro;
|
||||
}
|
||||
|
||||
.multiselect__single {
|
||||
@apply items-center flex m-0 text-sm max-h-[2.375rem] text-slate-800 dark:text-slate-100 bg-white dark:bg-slate-900 py-1 px-0.5;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
font-size: var(--font-size-small);
|
||||
margin: 0;
|
||||
max-height: 3.8rem;
|
||||
padding: var(--space-smaller) var(--space-micro);
|
||||
}
|
||||
|
||||
.multiselect__placeholder {
|
||||
@apply m-0 py-1 px-0.5;
|
||||
margin: 0;
|
||||
padding: var(--space-smaller) var(--space-micro);
|
||||
}
|
||||
|
||||
.multiselect__select {
|
||||
@apply min-h-[2.5rem];
|
||||
min-height: $multiselect-height;
|
||||
}
|
||||
|
||||
.multiselect--disabled .multiselect__current,
|
||||
.multiselect--disabled .multiselect__select {
|
||||
@apply bg-transparent;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.multiselect__tags-wrap {
|
||||
@apply flex-shrink-0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.multiselect-wrap--medium {
|
||||
$multiselect-height: 4.8rem;
|
||||
|
||||
.multiselect__tags,
|
||||
.multiselect__input {
|
||||
@apply items-center flex;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.multiselect__tags,
|
||||
.multiselect__input,
|
||||
.multiselect {
|
||||
@apply bg-white dark:bg-slate-900 text-slate-800 dark:text-slate-100 text-sm h-12 min-h-[3rem];
|
||||
background: var(--white);
|
||||
font-size: var(--font-size-small);
|
||||
height: $multiselect-height;
|
||||
min-height: $multiselect-height;
|
||||
}
|
||||
|
||||
.multiselect__input {
|
||||
@apply h-[2.875rem] min-h-[2.875rem];
|
||||
height: $multiselect-height - $space-micro;
|
||||
min-height: $multiselect-height - $space-micro;
|
||||
}
|
||||
|
||||
.multiselect__single {
|
||||
@apply items-center flex m-0 text-sm py-1 px-0.5 text-slate-800 dark:text-slate-100 bg-white dark:bg-slate-900;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
font-size: var(--font-size-small);
|
||||
margin: 0;
|
||||
padding: var(--space-smaller) var(--space-micro);
|
||||
}
|
||||
|
||||
.multiselect__placeholder {
|
||||
@apply m-0 py-1 px-0.5;
|
||||
margin: 0;
|
||||
padding: var(--space-smaller) var(--space-micro);
|
||||
}
|
||||
|
||||
.multiselect__select {
|
||||
@apply min-h-[3rem];
|
||||
min-height: $multiselect-height;
|
||||
}
|
||||
|
||||
.multiselect--disabled .multiselect__current,
|
||||
.multiselect--disabled .multiselect__select {
|
||||
@apply bg-transparent;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.multiselect__tags-wrap {
|
||||
@apply flex-shrink-0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
@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/plus-jakarta';
|
||||
@import 'shared/assets/fonts/inter';
|
||||
@import '../variables';
|
||||
@import '~shared/assets/stylesheets/ionicons';
|
||||
|
||||
@@ -1,112 +1,173 @@
|
||||
.settings {
|
||||
@apply overflow-auto;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// Resolve Button
|
||||
.button {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// User thumbnail and text
|
||||
.page-title {
|
||||
@include flex;
|
||||
@include flex-align($x: center, $y: middle);
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.wizard-box {
|
||||
.item {
|
||||
@apply cursor-pointer py-4 pr-4 pl-6 relative;
|
||||
@include background-light;
|
||||
|
||||
cursor: pointer;
|
||||
padding: $space-normal $space-normal $space-normal $space-medium;
|
||||
position: relative;
|
||||
|
||||
&::before,
|
||||
&::after {
|
||||
@apply bg-slate-75 dark:bg-slate-600 content-[''] h-full absolute top-5 w-0.5;
|
||||
background: $color-border;
|
||||
content: '';
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: $space-normal;
|
||||
width: 2px;
|
||||
}
|
||||
|
||||
&::before {
|
||||
@apply h-4 top-0;
|
||||
height: $space-normal;
|
||||
top: $zero;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
&::before {
|
||||
@apply h-0;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
&::after {
|
||||
@apply h-0;
|
||||
height: $zero;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
h3 {
|
||||
@apply text-woot-500 dark:text-woot-500;
|
||||
color: $color-woot;
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
background: $color-woot;
|
||||
}
|
||||
}
|
||||
|
||||
&.over {
|
||||
&::after {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
background: $color-woot;
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
background: $color-woot;
|
||||
}
|
||||
|
||||
& + .item {
|
||||
&::before {
|
||||
@apply bg-woot-500 dark:bg-woot-500;
|
||||
background: $color-woot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply text-slate-800 dark:text-slate-100 text-base pl-6;
|
||||
color: $color-body;
|
||||
font-size: $font-size-default;
|
||||
line-height: 1;
|
||||
padding-left: $space-medium;
|
||||
}
|
||||
|
||||
.completed {
|
||||
@apply text-green-500 dark:text-green-500 ml-1;
|
||||
color: $success-color;
|
||||
margin-left: $space-smaller;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-slate-600 dark:text-slate-300 text-sm m-0 pl-6;
|
||||
color: $color-light-gray;
|
||||
font-size: $font-size-small;
|
||||
margin: 0;
|
||||
padding-left: $space-medium;
|
||||
}
|
||||
|
||||
.step {
|
||||
@apply bg-slate-75 dark:bg-slate-600 rounded-2xl font-medium w-4 left-4 leading-4 z-[999] absolute text-center text-white dark:text-white text-xxs top-5;
|
||||
background: $color-border;
|
||||
border-radius: 20px;
|
||||
color: $color-white;
|
||||
font-size: $font-size-micro;
|
||||
font-weight: $font-weight-medium;
|
||||
height: $space-normal;
|
||||
left: $space-normal;
|
||||
line-height: $space-normal;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
top: $space-normal;
|
||||
width: $space-normal;
|
||||
z-index: 999;
|
||||
|
||||
i {
|
||||
@apply text-xxs;
|
||||
font-size: $font-size-micro;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wizard-body {
|
||||
@apply border border-slate-25 dark:border-slate-800/60 bg-white dark:bg-slate-900 h-full p-6;
|
||||
@include background-white;
|
||||
@include border-light;
|
||||
@include full-height();
|
||||
padding: $space-medium;
|
||||
|
||||
&.height-auto {
|
||||
@apply h-auto;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.settings--content {
|
||||
@apply my-2 mx-8;
|
||||
margin: $space-small $space-large;
|
||||
|
||||
.title {
|
||||
@apply font-medium;
|
||||
font-weight: $font-weight-medium;
|
||||
}
|
||||
|
||||
.code {
|
||||
@apply bg-slate-50 dark:bg-slate-800 overflow-auto p-2.5 whitespace-nowrap;
|
||||
background: $color-background;
|
||||
max-height: $space-mega;
|
||||
overflow: auto;
|
||||
padding: $space-one;
|
||||
white-space: nowrap;
|
||||
|
||||
code {
|
||||
@apply bg-transparent border-0;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.login-init {
|
||||
@apply pt-[30%] text-center;
|
||||
padding-top: 30%;
|
||||
text-align: center;
|
||||
|
||||
p {
|
||||
@apply p-6;
|
||||
padding: $space-medium;
|
||||
}
|
||||
|
||||
> a > img {
|
||||
@apply w-60;
|
||||
width: $space-larger * 5;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,41 @@
|
||||
// to be removed
|
||||
.integrations-wrap {
|
||||
.integration {
|
||||
background: $color-white;
|
||||
border: 1px solid $color-border;
|
||||
border-radius: $space-smaller;
|
||||
margin-bottom: $space-normal;
|
||||
padding: $space-normal;
|
||||
|
||||
.integration--image {
|
||||
display: flex;
|
||||
height: 10rem;
|
||||
width: 10rem;
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
padding: $space-medium;
|
||||
}
|
||||
}
|
||||
|
||||
.integration--type {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin: 0 var(--space-normal);
|
||||
}
|
||||
|
||||
.integration--title {
|
||||
font-size: var(--font-size-large);
|
||||
}
|
||||
|
||||
.button-wrap {
|
||||
@include flex;
|
||||
@include flex-align(center, middle);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.help-wrap {
|
||||
padding-left: $space-large;
|
||||
}
|
||||
|
||||
@@ -1,201 +1,207 @@
|
||||
$default-button-height: 4.0rem;
|
||||
|
||||
.button {
|
||||
@apply items-center inline-flex h-10 mb-0;
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
height: $default-button-height;
|
||||
margin-bottom: 0;
|
||||
|
||||
.button__content {
|
||||
@apply w-full;
|
||||
|
||||
img,
|
||||
svg {
|
||||
@apply inline-block;
|
||||
}
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
@apply px-2 py-0;
|
||||
padding: 0 var(--space-small);
|
||||
}
|
||||
|
||||
.icon--emoji + .button__content {
|
||||
@apply pl-2 rtl:pr-2 rtl:pl-0;
|
||||
.icon--emoji+.button__content {
|
||||
padding-left: var(--space-small);
|
||||
}
|
||||
|
||||
.icon--font + .button__content {
|
||||
@apply pl-2 rtl:pr-2 rtl:pl-0;
|
||||
.icon--font+.button__content {
|
||||
padding-left: var(--space-small);
|
||||
}
|
||||
|
||||
// @TODDO - Remove after moving all buttons to woot-button
|
||||
.icon + .button__content {
|
||||
@apply pl-2 w-auto rtl:pr-2 rtl:pl-0;
|
||||
.icon+.button__content {
|
||||
padding-left: var(--space-small);
|
||||
width: auto;
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
@apply flex justify-center text-center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&.round {
|
||||
@apply rounded-full;
|
||||
border-radius: $space-larger;
|
||||
}
|
||||
|
||||
// @TODO Use with link
|
||||
|
||||
&.compact {
|
||||
@apply pb-0 pt-0;
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
&.hollow {
|
||||
@apply border border-slate-200 dark:border-slate-600 text-woot-700 dark:text-woot-100 hover:bg-woot-50 dark:hover:bg-woot-900;
|
||||
border-color: var(--s-200);
|
||||
color: var(--w-700);
|
||||
|
||||
&.secondary {
|
||||
@apply text-slate-700 border-slate-200 dark:border-slate-600 dark:text-slate-100 hover:bg-slate-50 dark:hover:bg-slate-700;
|
||||
border-color: var(--s-200);
|
||||
color: var(--s-700);
|
||||
}
|
||||
|
||||
&.success {
|
||||
@apply text-green-700 dark:text-green-100 hover:bg-green-50 dark:hover:bg-green-800;
|
||||
border-color: var(--s-200);
|
||||
color: var(--g-700);
|
||||
}
|
||||
|
||||
&.alert {
|
||||
@apply text-red-700 dark:text-red-100 hover:bg-red-50 dark:hover:bg-red-800;
|
||||
border-color: var(--s-200);
|
||||
color: var(--r-700);
|
||||
}
|
||||
|
||||
&.warning {
|
||||
@apply text-yellow-700 dark:text-yellow-100 hover:bg-yellow-50 dark:hover:bg-yellow-800;
|
||||
border-color: var(--s-200);
|
||||
color: var(--y-700);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@apply bg-slate-75 dark:bg-slate-900 border-slate-100 dark:border-slate-700;
|
||||
background: var(--s-75);
|
||||
border-color: var(--s-100);
|
||||
|
||||
&.secondary {
|
||||
@apply border-slate-100 dark:border-slate-700;
|
||||
border-color: var(--s-100);
|
||||
}
|
||||
|
||||
&.success {
|
||||
@apply border-slate-100 dark:border-slate-700;
|
||||
border-color: var(--s-100);
|
||||
}
|
||||
|
||||
&.alert {
|
||||
@apply border-slate-100 dark:border-slate-700;
|
||||
border-color: var(--s-100);
|
||||
}
|
||||
|
||||
&.warning {
|
||||
@apply border-slate-100 dark:border-slate-700;
|
||||
border-color: var(--s-100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Smooth style
|
||||
&.smooth {
|
||||
@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;
|
||||
@include button-style(var(--w-50), var(--w-100), var(--w-700));
|
||||
|
||||
|
||||
&.secondary {
|
||||
@apply bg-slate-50 dark:bg-slate-700 text-slate-700 dark:text-slate-100 hover:bg-slate-100 dark:hover:bg-slate-800;
|
||||
@include button-style(var(--s-50), var(--s-100), var(--s-700));
|
||||
}
|
||||
|
||||
&.success {
|
||||
@apply bg-green-50 dark:bg-green-700 text-green-700 dark:text-green-100 hover:bg-green-100 dark:hover:bg-green-800;
|
||||
@include button-style(var(--g-50), var(--g-100), var(--g-700));
|
||||
}
|
||||
|
||||
&.alert {
|
||||
@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;
|
||||
@include button-style(var(--r-50), var(--r-100), var(--r-700));
|
||||
}
|
||||
|
||||
&.warning {
|
||||
@apply bg-yellow-100 dark:bg-yellow-100 text-yellow-700 dark:text-yellow-700 hover:bg-yellow-200 dark:hover:bg-yellow-200;
|
||||
@include button-style(var(--y-100), var(--y-200), var(--y-700));
|
||||
}
|
||||
}
|
||||
|
||||
&.clear {
|
||||
@apply text-woot-500 dark:text-woot-500;
|
||||
color: var(--w-700);
|
||||
|
||||
&.secondary {
|
||||
@apply text-slate-700 dark:text-slate-100;
|
||||
color: var(--s-700);
|
||||
}
|
||||
|
||||
&.success {
|
||||
@apply text-green-700 dark:text-green-100;
|
||||
color: var(--g-700);
|
||||
}
|
||||
|
||||
&.alert {
|
||||
@apply text-red-700 dark:text-red-100;
|
||||
color: var(--r-700);
|
||||
}
|
||||
|
||||
&.warning {
|
||||
@apply text-yellow-700 dark:text-yellow-700;
|
||||
color: var(--y-700);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@apply hover:bg-woot-50 dark:hover:bg-woot-900/50 hover:text-woot-500 dark:hover:text-woot-100;
|
||||
background: var(--w-50);
|
||||
|
||||
&.secondary {
|
||||
@apply hover:bg-slate-50 dark:hover:bg-slate-700;
|
||||
background: var(--s-50);
|
||||
}
|
||||
|
||||
&.success {
|
||||
@apply hover:bg-green-50 dark:hover:bg-green-800;
|
||||
background: var(--g-50);
|
||||
}
|
||||
|
||||
&.alert {
|
||||
@apply hover:bg-red-50 dark:hover:bg-red-800;
|
||||
background: var(--r-50);
|
||||
}
|
||||
|
||||
&.warning {
|
||||
@apply hover:bg-yellow-50 dark:hover:bg-yellow-100;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
&.secondary {
|
||||
@apply active:bg-slate-100 dark:active:bg-slate-900;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
&.secondary {
|
||||
@apply focus:bg-slate-50 dark:focus:bg-slate-700;
|
||||
background: var(--y-50);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sizes
|
||||
&.tiny {
|
||||
@apply h-6;
|
||||
height: var(--space-medium);
|
||||
|
||||
.icon + .button__content {
|
||||
@apply pl-1 rtl:pr-1 rtl:pl-0;
|
||||
.icon+.button__content {
|
||||
padding-left: var(--space-micro);
|
||||
}
|
||||
}
|
||||
|
||||
&.small {
|
||||
@apply h-8 pb-1 pt-1;
|
||||
height: var(--space-large);
|
||||
padding-bottom: var(--space-smaller);
|
||||
padding-top: var(--space-smaller);
|
||||
|
||||
.icon + .button__content {
|
||||
@apply pl-1 rtl:pr-1 rtl:pl-0;
|
||||
.icon+.button__content {
|
||||
padding-left: var(--space-smaller);
|
||||
}
|
||||
}
|
||||
|
||||
&.large {
|
||||
@apply h-12;
|
||||
height: var(--space-larger);
|
||||
}
|
||||
|
||||
&.button--only-icon {
|
||||
@apply justify-center pl-0 pr-0 w-10;
|
||||
justify-content: center;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
width: $default-button-height;
|
||||
|
||||
&.tiny {
|
||||
@apply w-6;
|
||||
width: var(--space-medium);
|
||||
}
|
||||
|
||||
&.small {
|
||||
@apply w-8;
|
||||
width: var(--space-large);
|
||||
}
|
||||
|
||||
&.large {
|
||||
@apply w-12;
|
||||
width: var(--space-larger);
|
||||
}
|
||||
}
|
||||
|
||||
&.link {
|
||||
@apply h-auto m-0 p-0;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
&:hover {
|
||||
@apply underline;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1 +1,71 @@
|
||||
// File to be removed
|
||||
$resolve-button-width: 13.2rem;
|
||||
|
||||
// Conversation header - Light BG
|
||||
.conv-header {
|
||||
@include background-white;
|
||||
@include flex;
|
||||
@include flex-align($x: justify, $y: middle);
|
||||
@include border-normal-bottom;
|
||||
padding: var(--space-small) var(--space-normal);
|
||||
|
||||
.multiselect-box {
|
||||
@include flex;
|
||||
@include flex-align($x: justify, $y: middle);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--space-smaller);
|
||||
margin-right: var(--space-small);
|
||||
width: 21.6rem;
|
||||
|
||||
.icon {
|
||||
color: $medium-gray;
|
||||
font-size: $font-size-default;
|
||||
line-height: 3.8rem;
|
||||
padding-left: $space-slab;
|
||||
padding-right: $space-smaller;
|
||||
}
|
||||
|
||||
.multiselect {
|
||||
border-radius: var(--border-radius-small);
|
||||
margin: 0;
|
||||
min-width: 0;
|
||||
|
||||
.multiselect__tags {
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// User thumbnail and text
|
||||
.user {
|
||||
@include flex;
|
||||
@include flex-align($x: center, $y: middle);
|
||||
margin-right: var(--space-normal);
|
||||
min-width: 0;
|
||||
|
||||
.user--profile__meta {
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
margin-left: var(--space-small);
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-actions-wrap {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,135 @@
|
||||
}
|
||||
|
||||
.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;
|
||||
|
||||
&.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;
|
||||
}
|
||||
|
||||
.conversation--user {
|
||||
font-size: var(--font-size-small);
|
||||
margin: 0 var(--space-small);
|
||||
text-transform: capitalize;
|
||||
|
||||
.label {
|
||||
left: var(--space-one);
|
||||
max-width: var(--space-jumbo);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
text-overflow: ellipsis;
|
||||
top: var(--space-one);
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.conversation--message {
|
||||
color: var(--color-body);
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: var(--font-weight-normal);
|
||||
height: var(--space-medium);
|
||||
line-height: var(--space-medium);
|
||||
margin: 0 var(--space-small);
|
||||
max-width: 96%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 27rem;
|
||||
}
|
||||
|
||||
.conversation--meta {
|
||||
@include flex;
|
||||
flex-direction: column;
|
||||
position: absolute;
|
||||
right: var(--space-normal);
|
||||
top: var(--space-normal);
|
||||
|
||||
.unread {
|
||||
@include round-corner;
|
||||
@include light-shadow;
|
||||
background: darken($success-color, 3%);
|
||||
color: var(--white);
|
||||
display: none;
|
||||
font-size: var(--font-size-micro);
|
||||
font-weight: var(--font-weight-black);
|
||||
height: var(--space-normal);
|
||||
line-height: var(--space-normal);
|
||||
margin-left: auto;
|
||||
margin-top: var(--space-smaller);
|
||||
min-width: var(--space-normal);
|
||||
padding: 0 var(--space-smaller);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.timestamp {
|
||||
color: $dark-gray;
|
||||
font-size: var(--font-size-micro);
|
||||
font-weight: var(--font-weight-normal);
|
||||
line-height: var(--space-normal);
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.unread-chat {
|
||||
.unread {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.conversation--message {
|
||||
font-weight: var(--font-weight-bold);
|
||||
}
|
||||
|
||||
.conversation--user {
|
||||
font-weight: var(--font-weight-bold);
|
||||
}
|
||||
}
|
||||
|
||||
&.compact {
|
||||
padding-left: 0;
|
||||
|
||||
.conversation--details {
|
||||
border-radius: var(--border-radius-small);
|
||||
margin-left: 0;
|
||||
padding-left: var(--space-two);
|
||||
padding-right: var(--space-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,211 +1,362 @@
|
||||
// scss-lint:disable MergeableSelector
|
||||
|
||||
@mixin bubble-with-types {
|
||||
@apply py-2 text-sm font-normal bg-woot-500 dark:bg-woot-500 relative px-4 m-0 text-white dark:text-white;
|
||||
padding: $space-small $space-normal;
|
||||
margin: 0;
|
||||
background: $color-woot;
|
||||
border-radius: $space-one;
|
||||
color: var(--white);
|
||||
font-size: $font-size-small;
|
||||
font-weight: $font-weight-normal;
|
||||
position: relative;
|
||||
|
||||
.message-text__wrap {
|
||||
@apply relative;
|
||||
position: relative;
|
||||
|
||||
.link {
|
||||
@apply text-white dark:text-white underline;
|
||||
color: var(--white);
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.image,
|
||||
.video {
|
||||
@apply cursor-pointer relative;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
||||
.modal-container {
|
||||
@apply text-center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal-image {
|
||||
@apply max-h-[76vh] max-w-[76vw];
|
||||
max-height: 90%;
|
||||
max-width: 90%;
|
||||
}
|
||||
|
||||
.modal-video {
|
||||
@apply max-h-[76vh] max-w-[76vw];
|
||||
max-height: 75vh;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
&::before {
|
||||
@apply bg-gradient-to-t from-transparent via-transparent to-slate-800 bg-repeat bg-clip-border bottom-0 h-[20%] content-[''] left-0 absolute w-full opacity-80;
|
||||
background-image: linear-gradient(
|
||||
-180deg,
|
||||
transparent 3%,
|
||||
$color-heading 130%
|
||||
);
|
||||
bottom: 0;
|
||||
content: '';
|
||||
height: 20%;
|
||||
left: 0;
|
||||
opacity: 0.8;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.video {
|
||||
.modal-container {
|
||||
width: auto;
|
||||
|
||||
.modal--close {
|
||||
z-index: var(--z-index-low);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.conversations-list-wrap {
|
||||
@include flex;
|
||||
border-right: 1px solid var(--s-50);
|
||||
flex-direction: column;
|
||||
|
||||
.load-more-conversations {
|
||||
font-size: $font-size-small;
|
||||
margin: 0;
|
||||
padding: $space-normal;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.end-of-list-text {
|
||||
padding: $space-normal;
|
||||
}
|
||||
|
||||
.conversations-list {
|
||||
flex: 1 1;
|
||||
overflow-y: auto;
|
||||
|
||||
@include breakpoint(large up) {
|
||||
@include scroll-on-hover;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-list__top {
|
||||
@include flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 var(--space-normal);
|
||||
}
|
||||
|
||||
.content-box {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.conversation-panel {
|
||||
@apply flex-shrink flex-grow basis-px flex flex-col overflow-y-auto relative h-full m-0 pb-4;
|
||||
@include flex;
|
||||
flex: 1 1 1px;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow-y: auto;
|
||||
padding-bottom: var(--space-normal);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.conversation-panel > li {
|
||||
@apply flex flex-shrink-0 flex-grow-0 flex-auto max-w-full mt-0 mr-0 mb-1 ml-0 relative first:mt-auto last:mb-0;
|
||||
@include flex;
|
||||
@include flex-shrink;
|
||||
margin: $zero $zero $space-micro;
|
||||
position: relative;
|
||||
|
||||
&:first-child {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.unread--toast {
|
||||
+ .right {
|
||||
@apply mb-1;
|
||||
margin-bottom: var(--space-micro);
|
||||
}
|
||||
|
||||
+ .left {
|
||||
@apply mb-0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
span {
|
||||
@apply shadow-lg rounded-full bg-woot-500 dark:bg-woot-500 text-white dark:text-white text-xs font-medium my-2.5 mx-auto px-2.5 py-1.5;
|
||||
@include elegant-card;
|
||||
@include round-corner;
|
||||
background: $color-woot;
|
||||
color: var(--white);
|
||||
font-size: $font-size-mini;
|
||||
font-weight: $font-weight-medium;
|
||||
margin: $space-one auto;
|
||||
padding: $space-smaller $space-two;
|
||||
}
|
||||
}
|
||||
|
||||
.bubble {
|
||||
@include bubble-with-types;
|
||||
@apply text-left break-words;
|
||||
text-align: left;
|
||||
word-wrap: break-word;
|
||||
|
||||
.aplayer {
|
||||
@apply shadow-none;
|
||||
box-shadow: none;
|
||||
font-family: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
&.left {
|
||||
.bubble {
|
||||
@apply border border-slate-50 dark:border-slate-700 bg-white dark:bg-slate-700 text-black-900 dark:text-slate-50 rounded-r-lg rounded-l mr-auto break-words;
|
||||
@include border-normal;
|
||||
background: $white;
|
||||
border-bottom-left-radius: $space-smaller;
|
||||
border-top-left-radius: $space-smaller;
|
||||
color: $color-body;
|
||||
margin-right: auto;
|
||||
word-break: break-word;
|
||||
|
||||
&.is-image {
|
||||
@apply rounded-lg;
|
||||
border-radius: var(--border-radius-large);
|
||||
}
|
||||
|
||||
.link {
|
||||
@apply text-woot-600 dark:text-woot-600;
|
||||
color: $color-primary-dark;
|
||||
}
|
||||
|
||||
.file {
|
||||
.text-block-title {
|
||||
@apply text-slate-700 dark:text-woot-300;
|
||||
color: $color-body;
|
||||
}
|
||||
|
||||
.icon-wrap {
|
||||
@apply text-woot-600 dark:text-woot-600;
|
||||
color: $color-woot;
|
||||
}
|
||||
|
||||
.download {
|
||||
@apply text-woot-600 dark:text-woot-600;
|
||||
color: $color-primary-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ .right {
|
||||
@apply mt-2.5;
|
||||
margin-top: $space-one;
|
||||
|
||||
.bubble {
|
||||
@apply rounded-tr-lg;
|
||||
border-top-right-radius: $space-one;
|
||||
}
|
||||
}
|
||||
|
||||
+ .unread--toast {
|
||||
+ .right {
|
||||
@apply mt-2.5;
|
||||
margin-top: $space-one;
|
||||
|
||||
.bubble {
|
||||
@apply rounded-tr-lg;
|
||||
border-top-right-radius: $space-one;
|
||||
}
|
||||
}
|
||||
|
||||
+ .left {
|
||||
@apply mt-0;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.right {
|
||||
@apply justify-end;
|
||||
@include flex-align(right, null);
|
||||
|
||||
.wrap {
|
||||
@apply flex items-end mr-4 text-right;
|
||||
align-items: flex-end;
|
||||
display: flex;
|
||||
margin-right: $space-normal;
|
||||
text-align: right;
|
||||
|
||||
.sender--info {
|
||||
@apply pt-2 pb-1 pr-0 pl-2;
|
||||
padding: var(--space-small) 0 var(--space-smaller) var(--space-small);
|
||||
}
|
||||
}
|
||||
|
||||
.bubble {
|
||||
@apply ml-auto break-words rounded-l-lg rounded-r;
|
||||
border-bottom-right-radius: $space-smaller;
|
||||
border-top-right-radius: $space-smaller;
|
||||
margin-left: auto;
|
||||
word-break: break-word;
|
||||
|
||||
&.is-private {
|
||||
@apply text-black-900 dark:text-black-900 relative border border-solid bg-[#fff3d5] border-[#ffd97a] dark:bg-[#fff3d5] dark:border-[#ffd97a];
|
||||
background: lighten($warning-color, 32%);
|
||||
border: 1px solid lighten($warning-color, 15%);
|
||||
color: $color-heading;
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
bottom: 0;
|
||||
color: $medium-gray;
|
||||
position: absolute;
|
||||
right: $space-one;
|
||||
top: $space-smaller + $space-micro;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-image {
|
||||
@apply rounded-lg;
|
||||
border-radius: var(--border-radius-large);
|
||||
}
|
||||
}
|
||||
|
||||
+ .left {
|
||||
@apply mt-2.5;
|
||||
margin-top: $space-one;
|
||||
|
||||
.bubble {
|
||||
@apply rounded-tl-lg;
|
||||
border-top-left-radius: $space-one;
|
||||
}
|
||||
}
|
||||
|
||||
+ .unread--toast {
|
||||
+ .left {
|
||||
@apply rounded-lg;
|
||||
margin-top: $space-one;
|
||||
|
||||
.bubble {
|
||||
@apply rounded-tl-lg;
|
||||
border-top-left-radius: $space-one;
|
||||
}
|
||||
}
|
||||
|
||||
+ .right {
|
||||
@apply mt-0;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.center {
|
||||
@apply items-center justify-center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
max-width: Min(31rem, 84%);
|
||||
@apply my-0 mx-4;
|
||||
--bubble-max-width: 49.6rem;
|
||||
margin: $zero $space-normal;
|
||||
max-width: Min(var(--bubble-max-width), 84%);
|
||||
|
||||
.sender--name {
|
||||
@apply text-xs mb-1;
|
||||
font-size: $font-size-mini;
|
||||
margin-bottom: $space-smaller;
|
||||
}
|
||||
}
|
||||
|
||||
.sender--thumbnail {
|
||||
@apply h-3 mr-3 mt-0.5 w-3 rounded-full;
|
||||
@include round-corner();
|
||||
height: $space-slab;
|
||||
margin-right: $space-one;
|
||||
margin-top: $space-micro;
|
||||
width: $space-slab;
|
||||
}
|
||||
|
||||
.activity-wrap {
|
||||
@apply flex justify-center text-sm my-1 mx-0 py-1 pr-0.5 pl-2.5 bg-slate-50 dark:bg-slate-600 text-slate-800 dark:text-slate-100 rounded-md border border-slate-100 dark:border-slate-600 border-solid;
|
||||
background: var(--s-50);
|
||||
border: 1px solid var(--s-100);
|
||||
border-radius: var(--border-radius-medium);
|
||||
display: flex;
|
||||
font-size: var(--font-size-small);
|
||||
justify-content: center;
|
||||
margin: var(--space-smaller) 0;
|
||||
padding: var(--space-smaller) var(--space-micro) var(--space-smaller)
|
||||
var(--space-one);
|
||||
|
||||
.is-text {
|
||||
@apply inline-flex items-center text-start 2xl:flex;
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
text-align: start;
|
||||
|
||||
@include breakpoint(xxxlarge up) {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.activity-wrap .message-text__wrap {
|
||||
.text-content p {
|
||||
@apply mb-0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.conversation-footer {
|
||||
@apply flex relative flex-col;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.typing-indicator-wrap {
|
||||
@apply items-center flex h-0 absolute w-full -top-8;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
top: -$space-large;
|
||||
width: 100%;
|
||||
|
||||
.typing-indicator {
|
||||
@include elegant-card;
|
||||
@include round-corner;
|
||||
@apply py-2 pr-4 pl-5 bg-white dark:bg-slate-700 text-slate-800 dark:text-slate-100 text-xs font-semibold my-2.5 mx-auto;
|
||||
background: var(--white);
|
||||
color: $color-light-gray;
|
||||
font-size: $font-size-mini;
|
||||
font-weight: $font-weight-bold;
|
||||
margin: $space-one auto;
|
||||
padding: $space-small $space-normal $space-small $space-two;
|
||||
|
||||
.gif {
|
||||
@apply ml-2 w-6;
|
||||
margin-left: $space-small;
|
||||
width: $space-medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,15 +368,16 @@
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
@apply text-slate-800 dark:text-slate-100;
|
||||
color: var(--color-body);
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-woot-500 dark:text-woot-500 underline;
|
||||
color: var(--color-woot);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
@apply mb-0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,14 +388,16 @@
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
@apply text-white dark:text-white;
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-white dark:text-white underline;
|
||||
color: var(--white);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
@apply mb-0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,5 @@
|
||||
// scss-lint:disable QualifyingElement
|
||||
|
||||
label {
|
||||
@apply text-slate-800 dark:text-slate-200;
|
||||
}
|
||||
|
||||
textarea {
|
||||
@apply bg-white dark:bg-slate-900 focus:bg-white focus:dark:bg-slate-900 text-slate-900 dark:text-slate-100 border-slate-200 dark:border-slate-600;
|
||||
}
|
||||
|
||||
input {
|
||||
@apply bg-white dark:bg-slate-900 focus:bg-white focus:dark:bg-slate-900 text-slate-900 dark:text-slate-100 border-slate-200 dark:border-slate-600;
|
||||
|
||||
&[disabled] {
|
||||
@apply bg-slate-200 dark:bg-slate-700 text-slate-400 dark:text-slate-400 border-slate-200 dark:border-slate-600;
|
||||
}
|
||||
}
|
||||
|
||||
input[type='file'] {
|
||||
@apply bg-white dark:bg-slate-800;
|
||||
}
|
||||
|
||||
select {
|
||||
@apply bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 border-slate-200 dark:border-slate-600;
|
||||
}
|
||||
|
||||
.error {
|
||||
input[type='color'],
|
||||
input[type='date'],
|
||||
@@ -43,11 +19,17 @@ select {
|
||||
textarea,
|
||||
select,
|
||||
.multiselect > .multiselect__tags {
|
||||
@apply border border-solid border-red-400 dark:border-red-400;
|
||||
@include thin-border(var(--r-400));
|
||||
}
|
||||
|
||||
.message {
|
||||
@apply text-red-400 dark:text-red-400 block text-sm mb-2.5 w-full;
|
||||
color: var(--r-400);
|
||||
display: block;
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: $font-weight-normal;
|
||||
margin-bottom: $space-one;
|
||||
margin-top: -$space-normal;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,19 +42,22 @@ input {
|
||||
}
|
||||
|
||||
.input-wrap {
|
||||
@apply text-slate-800 dark:text-slate-100 text-sm font-medium;
|
||||
color: $color-heading;
|
||||
font-size: $font-size-small;
|
||||
font-weight: $font-weight-medium;
|
||||
}
|
||||
|
||||
.help-text {
|
||||
@apply font-normal text-slate-600 dark:text-slate-400;
|
||||
font-weight: $font-weight-normal;
|
||||
}
|
||||
|
||||
.input-group.small {
|
||||
input {
|
||||
@apply text-sm h-8;
|
||||
font-size: var(--font-size-small);
|
||||
height: var(--space-large);
|
||||
}
|
||||
|
||||
.error {
|
||||
@apply border-red-400 dark:border-red-400;
|
||||
border-color: var(--r-400);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,79 +1,117 @@
|
||||
@import '~dashboard/assets/scss/variables';
|
||||
@import '~dashboard/assets/scss/mixins';
|
||||
|
||||
.modal-mask {
|
||||
// @include flex;
|
||||
// @include flex-align(center, middle);
|
||||
@apply flex items-center justify-center bg-modal dark:bg-modal z-[9990] h-full left-0 fixed top-0 w-full;
|
||||
@include flex;
|
||||
@include flex-align(center, middle);
|
||||
background-color: $masked-bg;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 9990;
|
||||
}
|
||||
|
||||
.modal--close {
|
||||
@apply absolute right-2 rtl:right-[unset] rtl:left-2 top-2;
|
||||
position: absolute;
|
||||
right: $space-small;
|
||||
top: $space-small;
|
||||
|
||||
&:hover {
|
||||
background: $color-background;
|
||||
}
|
||||
}
|
||||
|
||||
.page-top-bar {
|
||||
@apply px-8 pt-9 pb-0;
|
||||
padding: $space-large $space-large $zero;
|
||||
|
||||
img {
|
||||
@apply max-h-[3.75rem];
|
||||
max-height: 6rem;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-container {
|
||||
@apply shadow-md rounded-sm max-h-full overflow-auto relative w-[37.5rem];
|
||||
@include normal-shadow;
|
||||
|
||||
background-color: $color-white;
|
||||
border-radius: $space-smaller;
|
||||
max-height: 100%;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
width: 60rem;
|
||||
|
||||
&.medium {
|
||||
@apply max-w-[80%] w-[56.25rem];
|
||||
max-width: 80%;
|
||||
width: 90rem;
|
||||
}
|
||||
|
||||
.content-box {
|
||||
@apply h-auto p-0;
|
||||
height: auto;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply text-slate-800 dark:text-slate-100 text-lg font-semibold;
|
||||
color: $color-heading;
|
||||
font-size: $font-size-medium;
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-sm m-0 p-0 text-slate-600 mt-2 text-sm dark:text-slate-300;
|
||||
font-size: $font-size-small;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.content {
|
||||
@apply p-8;
|
||||
padding: $space-large;
|
||||
}
|
||||
|
||||
form,
|
||||
.modal-content {
|
||||
@apply pt-4 pb-8 px-8 self-center;
|
||||
align-self: center;
|
||||
padding: $space-large;
|
||||
|
||||
a {
|
||||
@apply p-4;
|
||||
padding: $space-normal;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
// @include flex;
|
||||
// @include flex-align($x: flex-end, $y: middle);
|
||||
@apply flex justify-end items-center py-2 px-0 gap-2;
|
||||
@include flex;
|
||||
@include flex-align($x: flex-end, $y: middle);
|
||||
padding: $space-small $zero;
|
||||
|
||||
.button {
|
||||
margin-left: var(--space-small);
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
.button {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.justify-content-end {
|
||||
@apply justify-end;
|
||||
justify-content: end;
|
||||
}
|
||||
}
|
||||
|
||||
.delete-item {
|
||||
@apply p-8;
|
||||
padding: $space-large;
|
||||
|
||||
button {
|
||||
@apply m-0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-enter,
|
||||
.modal-leave {
|
||||
@apply opacity-0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.modal-enter .modal-container,
|
||||
.modal-leave .modal-container {
|
||||
transform: scale(1.1);
|
||||
// @apply transform scale-110;
|
||||
}
|
||||
|
||||
@@ -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: 3rem;
|
||||
min-height: 4.8rem;
|
||||
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: 3rem;
|
||||
min-height: 4.8rem;
|
||||
padding: var(--space-normal) 0 0;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
@@ -58,3 +58,31 @@
|
||||
text-transform: capitalize;
|
||||
}
|
||||
}
|
||||
|
||||
.report-bar {
|
||||
@include background-white;
|
||||
@include border-light;
|
||||
margin: var(--space-minus-micro) 0;
|
||||
padding: var(--space-small) var(--space-medium);
|
||||
|
||||
.chart-container {
|
||||
@include flex;
|
||||
@include flex-align(center, middle);
|
||||
flex-direction: column;
|
||||
|
||||
div {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
color: $color-gray;
|
||||
font-size: var(--font-size-default);
|
||||
margin: var(--space-jumbo);
|
||||
}
|
||||
|
||||
.business-hours {
|
||||
margin: var(--space-normal);
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,18 @@
|
||||
margin: 0 var(--space-small);
|
||||
}
|
||||
|
||||
.business-hours {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
margin-left: auto;
|
||||
padding-right: var(--space-normal);
|
||||
}
|
||||
|
||||
.business-hours-text {
|
||||
font-size: var(--font-size-small);
|
||||
margin: 0 var(--space-small);
|
||||
}
|
||||
|
||||
.switch {
|
||||
margin-bottom: var(--space-zero);
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
|
||||
.dropdown-pane {
|
||||
bottom: 3.75rem;
|
||||
bottom: 6rem;
|
||||
display: block;
|
||||
visibility: visible;
|
||||
width: fit-content;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.ui-snackbar-container {
|
||||
left: 0;
|
||||
margin: 0 auto;
|
||||
max-width: 25rem;
|
||||
max-width: 40rem;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
@@ -16,9 +16,9 @@
|
||||
border-radius: $space-smaller;
|
||||
display: inline-flex;
|
||||
margin-bottom: $space-small;
|
||||
max-width: 25rem;
|
||||
min-height: 1.875rem;
|
||||
min-width: 15rem;
|
||||
max-width: 40rem;
|
||||
min-height: 3rem;
|
||||
min-width: 24rem;
|
||||
padding: $space-slab $space-medium;
|
||||
text-align: left;
|
||||
}
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
.ui-snackbar-action {
|
||||
margin-left: auto;
|
||||
padding-left: 1.875rem;
|
||||
padding-left: 3rem;
|
||||
|
||||
button {
|
||||
background: none;
|
||||
|
||||
@@ -1 +1,42 @@
|
||||
// To be removed
|
||||
.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 {
|
||||
padding: $space-jumbo $space-smaller;
|
||||
|
||||
.title,
|
||||
.message {
|
||||
display: block;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: $font-size-giga;
|
||||
font-weight: $font-weight-feather;
|
||||
}
|
||||
|
||||
.message {
|
||||
color: $color-gray;
|
||||
margin: $space-normal auto;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin-top: $space-medium;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,69 +1,100 @@
|
||||
.tabs--container {
|
||||
@apply flex;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.tabs--container--with-border {
|
||||
@apply border-b border-slate-50 dark:border-slate-800/50;
|
||||
@include border-normal-bottom;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
@apply border-r-0 border-l-0 border-t-0 flex min-w-[6.25rem] py-0 px-4;
|
||||
border-left-width: 0;
|
||||
border-right-width: 0;
|
||||
border-top-width: 0;
|
||||
display: flex;
|
||||
min-width: var(--space-mega);
|
||||
padding: 0 var(--space-normal);
|
||||
}
|
||||
|
||||
.tabs--with-scroll {
|
||||
@apply overflow-hidden py-0 px-1;
|
||||
max-width: calc(100% - 64px);
|
||||
overflow: hidden;
|
||||
padding: 0 var(--space-smaller);
|
||||
}
|
||||
|
||||
.tabs--scroll-button {
|
||||
@apply items-center rounded-none cursor-pointer flex h-auto justify-center min-w-[2rem];
|
||||
align-items: center;
|
||||
border-radius: 0;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
height: auto;
|
||||
justify-content: center;
|
||||
min-width: var(--space-large);
|
||||
}
|
||||
|
||||
// Tab chat type
|
||||
.tab--chat-type {
|
||||
@apply flex;
|
||||
@include flex;
|
||||
|
||||
.tabs-title {
|
||||
a {
|
||||
@apply text-base font-medium py-3;
|
||||
font-size: var(--font-size-default);
|
||||
font-weight: var(--font-weight-medium);
|
||||
padding-bottom: var(--space-slab);
|
||||
padding-top: var(--space-slab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabs-title {
|
||||
@apply flex-shrink-0 my-0 mx-2;
|
||||
flex-shrink: 0;
|
||||
margin: 0 var(--space-small);
|
||||
|
||||
.badge {
|
||||
@apply bg-slate-50 dark:bg-slate-800 rounded-md text-slate-600 dark:text-slate-100 h-5 flex items-center justify-center text-xxs font-semibold my-0 mx-1 px-1 py-0;
|
||||
background: var(--color-background);
|
||||
border-radius: var(--space-small);
|
||||
color: var(--color-gray);
|
||||
font-size: var(--font-size-micro);
|
||||
font-weight: var(--font-weight-black);
|
||||
margin: 0 var(--space-smaller);
|
||||
padding: var(--space-smaller);
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
@apply ml-0;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
@apply mr-0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
a {
|
||||
@apply text-slate-800 dark:text-slate-100;
|
||||
color: darken($medium-gray, 20%);
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
@apply flex items-center flex-row border-b border-transparent text-slate-600 dark:text-slate-200 text-sm top-[1px] relative;
|
||||
align-items: center;
|
||||
border-bottom: 2px solid transparent;
|
||||
color: $medium-gray;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
font-size: var(--font-size-small);
|
||||
position: relative;
|
||||
top: 1px;
|
||||
transition: border-color 0.15s $swift-ease-out-function;
|
||||
}
|
||||
|
||||
&.is-active {
|
||||
a {
|
||||
@apply border-b border-woot-500 text-woot-500 dark:text-woot-500;
|
||||
border-bottom-color: var(--color-woot);
|
||||
color: var(--color-woot);
|
||||
}
|
||||
|
||||
.badge {
|
||||
@apply bg-woot-50 dark:bg-woot-500 text-woot-500 dark:text-woot-50 dark:bg-opacity-40;
|
||||
background: $color-extra-light-blue;
|
||||
color: var(--color-woot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
table {
|
||||
@apply border-spacing-0 text-sm;
|
||||
border-spacing: 0;
|
||||
font-size: var(--font-size-small);
|
||||
|
||||
thead {
|
||||
th {
|
||||
@apply font-semibold tracking-[1px] text-left uppercase text-slate-900 dark:text-slate-200;
|
||||
font-weight: var(--font-weight-bold);
|
||||
text-align: left;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
tr {
|
||||
@apply border-b border-slate-50 dark:border-slate-800/30;
|
||||
border-bottom: 1px solid var(--color-border-light);
|
||||
}
|
||||
|
||||
td {
|
||||
@apply p-2.5 text-slate-700 dark:text-slate-100;
|
||||
padding: var(--space-small);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,68 +24,37 @@ table {
|
||||
.woot-table {
|
||||
tr {
|
||||
.show-if-hover {
|
||||
opacity: 0;
|
||||
transition: opacity 0.2s $swift-ease-out-function;
|
||||
@apply opacity-0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.show-if-hover {
|
||||
@apply opacity-100;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.agent-name {
|
||||
@apply block font-medium capitalize;
|
||||
display: block;
|
||||
font-weight: var(--font-weight-medium);
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.woot-thumbnail {
|
||||
@apply rounded-full h-[3.125rem] w-[3.125rem];
|
||||
border-radius: 50%;
|
||||
height: 5rem;
|
||||
width: 5rem;
|
||||
}
|
||||
|
||||
.button-wrapper {
|
||||
@apply flex justify-start flex-row min-w-[12.5rem] gap-1;
|
||||
@include flex-align(left, null);
|
||||
@include flex;
|
||||
flex-direction: row;
|
||||
min-width: 20rem;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ve-table {
|
||||
.ve-table-container.ve-table-border-around {
|
||||
@apply border-slate-200 dark:border-slate-700;
|
||||
}
|
||||
|
||||
.ve-table-content {
|
||||
.ve-table-header .ve-table-header-tr .ve-table-header-th {
|
||||
@apply bg-slate-50 dark:bg-slate-800 text-slate-800 dark:text-slate-100 border-slate-100 dark:border-slate-700/50;
|
||||
}
|
||||
|
||||
.ve-table-body .ve-table-body-tr .ve-table-body-td {
|
||||
@apply bg-white dark:bg-slate-900 text-slate-900 dark:text-slate-100 border-slate-75 dark:border-slate-800;
|
||||
}
|
||||
|
||||
.ve-table-body.ve-table-row-hover .ve-table-body-tr:hover td {
|
||||
@apply bg-slate-50 dark:bg-slate-700 text-slate-800 dark:text-slate-100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-pagination {
|
||||
.ve-pagination-total {
|
||||
@apply text-slate-600 dark:text-slate-200;
|
||||
}
|
||||
|
||||
.ve-pagination-goto {
|
||||
@apply text-slate-600 dark:text-slate-200;
|
||||
}
|
||||
|
||||
.ve-pagination-li {
|
||||
@apply bg-white dark:bg-slate-900 text-slate-600 dark:text-slate-200 border-slate-75 dark:border-slate-700;
|
||||
}
|
||||
|
||||
.ve-pagination-goto-input {
|
||||
@apply bg-white dark:bg-slate-900 text-slate-600 dark:text-slate-200;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
<template>
|
||||
<div class="-mt-px text-sm">
|
||||
<button
|
||||
class="flex items-center select-none w-full bg-slate-50 dark:bg-slate-800 border border-l-0 border-r-0 border-solid m-0 border-slate-100 dark:border-slate-700/50 cursor-grab justify-between py-2 px-4 drag-handle"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<div class="flex justify-between mb-0.5">
|
||||
<emoji-or-icon class="inline-block w-5" :icon="icon" :emoji="emoji" />
|
||||
<h5
|
||||
class="text-slate-800 text-sm dark:text-slate-100 mb-0 py-0 pr-2 pl-0"
|
||||
>
|
||||
<div class="cw-accordion">
|
||||
<button class="cw-accordion--title drag-handle" @click="$emit('click')">
|
||||
<div class="cw-accordion--title-wrap">
|
||||
<emoji-or-icon class="icon-or-emoji" :icon="icon" :emoji="emoji" />
|
||||
<h5>
|
||||
{{ title }}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="flex flex-row">
|
||||
<div class="button-icon--wrap">
|
||||
<slot name="button" />
|
||||
<div class="flex justify-end w-3 text-woot-500">
|
||||
<div class="chevron-icon__wrap">
|
||||
<fluent-icon v-if="isOpen" size="24" icon="subtract" type="solid" />
|
||||
<fluent-icon v-else size="24" icon="add" type="solid" />
|
||||
</div>
|
||||
@@ -22,8 +17,8 @@
|
||||
</button>
|
||||
<div
|
||||
v-if="isOpen"
|
||||
class="bg-white dark:bg-slate-900"
|
||||
:class="compact ? 'p-0' : 'p-4'"
|
||||
class="cw-accordion--content"
|
||||
:class="{ compact: compact }"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
@@ -61,3 +56,67 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cw-accordion {
|
||||
// This is done to fix contact sidebar border issues
|
||||
// If you are using it else, find a fix to remove this hack
|
||||
margin-top: -1px;
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
.cw-accordion--title {
|
||||
align-items: center;
|
||||
background: var(--s-50);
|
||||
border-bottom: 1px solid var(--s-100);
|
||||
border-top: 1px solid var(--s-100);
|
||||
cursor: grab;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 0;
|
||||
padding: var(--space-small) var(--space-normal);
|
||||
user-select: none;
|
||||
width: 100%;
|
||||
|
||||
h5 {
|
||||
font-size: var(--font-size-normal);
|
||||
margin-bottom: 0;
|
||||
padding: 0 var(--space-small) 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.cw-accordion--title-wrap {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: var(--space-micro);
|
||||
}
|
||||
|
||||
.title-icon__wrap {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.icon-or-emoji {
|
||||
display: inline-block;
|
||||
width: var(--space-two);
|
||||
}
|
||||
|
||||
.button-icon--wrap {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.chevron-icon__wrap {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: var(--space-slab);
|
||||
color: var(--w-500);
|
||||
}
|
||||
|
||||
.cw-accordion--content {
|
||||
padding: var(--space-normal);
|
||||
|
||||
&.compact {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
<template>
|
||||
<button
|
||||
class="sm:w-[50%] md:w-[34%] lg:w-[25%] channel"
|
||||
@click="$emit('click')"
|
||||
>
|
||||
<button class="small-6 medium-4 large-3 channel" @click="$emit('click')">
|
||||
<img :src="src" :alt="title" />
|
||||
<h3 class="channel__title">
|
||||
{{ title }}
|
||||
@@ -27,36 +24,44 @@ export default {
|
||||
|
||||
<style scoped lang="scss">
|
||||
.inactive {
|
||||
img {
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
&.channel:hover {
|
||||
@apply border-transparent shadow-none cursor-not-allowed;
|
||||
}
|
||||
filter: grayscale(100%);
|
||||
}
|
||||
|
||||
.channel {
|
||||
@apply bg-white dark:bg-slate-900 cursor-pointer flex flex-col transition-all duration-200 ease-in -m-px py-4 px-0 items-center border border-solid border-slate-25 dark:border-slate-800;
|
||||
|
||||
background: var(--white);
|
||||
border: 1px solid var(--color-border-light);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: -1px;
|
||||
padding: var(--space-normal) 0;
|
||||
transition: all 0.2s ease-in;
|
||||
align-items: center;
|
||||
&:hover {
|
||||
@apply border-woot-500 dark:border-woot-500 shadow-md z-50;
|
||||
border: 1px solid var(--w-500);
|
||||
box-shadow: var(--shadow-medium);
|
||||
z-index: var(--z-index-high);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
@apply opacity-60;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
img {
|
||||
@apply w-[50%] my-4 mx-auto;
|
||||
margin: var(--space-normal) auto;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.channel__title {
|
||||
@apply text-slate-800 dark:text-slate-100 text-base text-center capitalize;
|
||||
color: var(--color-body);
|
||||
font-size: var(--font-size-default);
|
||||
text-align: center;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply text-slate-600 dark:text-slate-300 w-full text-sm;
|
||||
color: var(--b-500);
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="conversations-list-wrap flex-shrink-0 flex-basis-custom overflow-hidden flex flex-col border-r rtl:border-r-0 rtl:border-l border-slate-50 dark:border-slate-800/50"
|
||||
class="conversations-list-wrap"
|
||||
:class="{
|
||||
hide: !showConversationList,
|
||||
'list--full-width': isOnExpandedLayout,
|
||||
@@ -8,28 +8,26 @@
|
||||
>
|
||||
<slot />
|
||||
<div
|
||||
class="flex items-center justify-between py-0 px-4"
|
||||
:class="{
|
||||
'pb-3 border-b border-slate-75 dark:border-slate-700': hasAppliedFiltersOrActiveFolders,
|
||||
}"
|
||||
class="chat-list__top"
|
||||
:class="{ filter__applied: hasAppliedFiltersOrActiveFolders }"
|
||||
>
|
||||
<div class="flex max-w-[85%] justify-center items-center">
|
||||
<div class="flex-center chat-list__title">
|
||||
<h1
|
||||
class="text-xl break-words overflow-hidden whitespace-nowrap text-ellipsis text-black-800 dark:text-slate-100 overflow-hidden whitespace-nowrap text-ellipsis mb-0"
|
||||
class="page-sub-title text-truncate margin-bottom-0"
|
||||
:title="pageTitle"
|
||||
>
|
||||
{{ pageTitle }}
|
||||
</h1>
|
||||
<span
|
||||
v-if="!hasAppliedFiltersOrActiveFolders"
|
||||
class="p-1 my-0.5 mx-1 rounded-md capitalize bg-slate-50 dark:bg-slate-800 text-xxs text-slate-600 dark:text-slate-300"
|
||||
class="conversation--status-pill"
|
||||
>
|
||||
{{
|
||||
this.$t(`CHAT_LIST.CHAT_STATUS_FILTER_ITEMS.${activeStatus}.TEXT`)
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<div class="filter--actions">
|
||||
<div v-if="hasAppliedFilters && !hasActiveFolders">
|
||||
<woot-button
|
||||
v-tooltip.top-end="$t('FILTER.CUSTOM_VIEWS.ADD.SAVE_BUTTON')"
|
||||
@@ -49,14 +47,6 @@
|
||||
/>
|
||||
</div>
|
||||
<div v-if="hasActiveFolders">
|
||||
<woot-button
|
||||
v-tooltip.top-end="$t('FILTER.CUSTOM_VIEWS.EDIT.EDIT_BUTTON')"
|
||||
size="tiny"
|
||||
variant="smooth"
|
||||
color-scheme="secondary"
|
||||
icon="edit"
|
||||
@click="onToggleAdvanceFiltersModal"
|
||||
/>
|
||||
<woot-button
|
||||
v-tooltip.top-end="$t('FILTER.CUSTOM_VIEWS.DELETE.DELETE_BUTTON')"
|
||||
size="tiny"
|
||||
@@ -106,10 +96,7 @@
|
||||
@chatTabChange="updateAssigneeTab"
|
||||
/>
|
||||
|
||||
<p
|
||||
v-if="!chatListLoading && !conversationList.length"
|
||||
class="overflow-auto p-4 flex justify-center items-center"
|
||||
>
|
||||
<p v-if="!chatListLoading && !conversationList.length" class="content-box">
|
||||
{{ $t('CHAT_LIST.LIST.404') }}
|
||||
</p>
|
||||
<conversation-bulk-actions
|
||||
@@ -128,46 +115,47 @@
|
||||
/>
|
||||
<div
|
||||
ref="activeConversation"
|
||||
class="conversations-list flex-1"
|
||||
:class="{ 'overflow-hidden': isContextMenuOpen }"
|
||||
class="conversations-list"
|
||||
:class="{ 'is-context-menu-open': isContextMenuOpen }"
|
||||
>
|
||||
<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>
|
||||
<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 v-if="chatListLoading" class="text-center">
|
||||
<span class="spinner mt-4 mb-4" />
|
||||
<span class="spinner" />
|
||||
</div>
|
||||
|
||||
<woot-button
|
||||
v-if="!hasCurrentPageEndReached && !chatListLoading"
|
||||
variant="clear"
|
||||
size="expanded"
|
||||
class="load-more--button"
|
||||
@click="loadMoreConversations"
|
||||
>
|
||||
{{ $t('CHAT_LIST.LOAD_MORE_CONVERSATIONS') }}
|
||||
</woot-button>
|
||||
|
||||
<p v-if="showEndOfListMessage" class="text-center text-muted p-4">
|
||||
<p
|
||||
v-if="showEndOfListMessage"
|
||||
class="text-center text-muted end-of-list-text"
|
||||
>
|
||||
{{ $t('CHAT_LIST.EOF') }}
|
||||
</p>
|
||||
</div>
|
||||
@@ -180,11 +168,8 @@
|
||||
v-if="showAdvancedFilters"
|
||||
:initial-filter-types="advancedFilterTypes"
|
||||
:initial-applied-filters="appliedFilter"
|
||||
:active-folder-name="activeFolderName"
|
||||
:on-close="closeAdvanceFiltersModal"
|
||||
:is-folder-view="hasActiveFolders"
|
||||
@applyFilter="onApplyFilter"
|
||||
@updateFolder="onUpdateSavedFilter"
|
||||
/>
|
||||
</woot-modal>
|
||||
</div>
|
||||
@@ -208,9 +193,6 @@ import DeleteCustomViews from 'dashboard/routes/dashboard/customviews/DeleteCust
|
||||
import ConversationBulkActions from './widgets/conversation/conversationBulkActions/Index.vue';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import filterMixin from 'shared/mixins/filterMixin';
|
||||
import languages from 'dashboard/components/widgets/conversation/advancedFilterItems/languages';
|
||||
import countries from 'shared/constants/countries';
|
||||
import { generateValuesForEditCustomViews } from 'dashboard/helper/customViewsHelper';
|
||||
|
||||
import {
|
||||
hasPressedAltAndJKey,
|
||||
@@ -307,11 +289,6 @@ export default {
|
||||
appliedFilters: 'getAppliedConversationFilters',
|
||||
folders: 'customViews/getCustomViews',
|
||||
inboxes: 'inboxes/getInboxes',
|
||||
agentList: 'agents/getAgents',
|
||||
teamsList: 'teams/getTeams',
|
||||
inboxesList: 'inboxes/getInboxes',
|
||||
campaigns: 'campaigns/getAllCampaigns',
|
||||
labels: 'labels/getLabels',
|
||||
}),
|
||||
hasAppliedFilters() {
|
||||
return this.appliedFilters.length !== 0;
|
||||
@@ -474,9 +451,6 @@ export default {
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
activeFolderName() {
|
||||
return this.activeFolder?.name;
|
||||
},
|
||||
activeTeam() {
|
||||
if (this.teamId) {
|
||||
return this.$store.getters['teams/getTeam'](this.teamId);
|
||||
@@ -509,7 +483,9 @@ export default {
|
||||
this.resetAndFetchData();
|
||||
},
|
||||
activeFolder() {
|
||||
this.resetAndFetchData();
|
||||
if (!this.hasAppliedFilters) {
|
||||
this.resetAndFetchData();
|
||||
}
|
||||
},
|
||||
chatLists() {
|
||||
this.chatsOnView = this.conversationList;
|
||||
@@ -520,10 +496,6 @@ export default {
|
||||
this.$store.dispatch('setChatSortFilter', this.activeSortBy);
|
||||
this.resetAndFetchData();
|
||||
|
||||
if (this.hasActiveFolders) {
|
||||
this.$store.dispatch('campaigns/get');
|
||||
}
|
||||
|
||||
bus.$on('fetch_conversation_stats', () => {
|
||||
this.$store.dispatch('conversationStats/get', this.conversationFilters);
|
||||
});
|
||||
@@ -536,15 +508,6 @@ export default {
|
||||
this.$store.dispatch('emptyAllConversations');
|
||||
this.fetchFilteredConversations(payload);
|
||||
},
|
||||
onUpdateSavedFilter(payload, folderName) {
|
||||
const payloadData = {
|
||||
...this.activeFolder,
|
||||
name: folderName,
|
||||
query: filterQueryGenerator(payload),
|
||||
};
|
||||
this.$store.dispatch('customViews/update', payloadData);
|
||||
this.closeAdvanceFiltersModal();
|
||||
},
|
||||
onClickOpenAddFoldersModal() {
|
||||
this.showAddFoldersModal = true;
|
||||
},
|
||||
@@ -558,70 +521,15 @@ export default {
|
||||
this.showDeleteFoldersModal = false;
|
||||
},
|
||||
onToggleAdvanceFiltersModal() {
|
||||
if (!this.hasAppliedFilters && !this.hasActiveFolders) {
|
||||
if (!this.hasAppliedFilters) {
|
||||
this.initializeExistingFilterToModal();
|
||||
}
|
||||
if (this.hasActiveFolders) {
|
||||
this.initializeFolderToFilterModal(this.activeFolder);
|
||||
}
|
||||
this.showAdvancedFilters = true;
|
||||
},
|
||||
closeAdvanceFiltersModal() {
|
||||
this.showAdvancedFilters = false;
|
||||
this.appliedFilter = [];
|
||||
},
|
||||
setParamsForEditFolderModal() {
|
||||
// Here we are setting the params for edit folder modal to show the existing values.
|
||||
|
||||
// For agent, team, inboxes,and campaigns we get only the id's from the query.
|
||||
// So we are mapping the id's to the actual values.
|
||||
|
||||
// For labels we get the name of the label from the query.
|
||||
// If we delete the label from the label list then we will not be able to show the label name.
|
||||
|
||||
// For custom attributes we get only attribute key.
|
||||
// So we are mapping it to find the input type of the attribute to show in the edit folder modal.
|
||||
const params = {
|
||||
agents: this.agentList,
|
||||
teams: this.teamsList,
|
||||
inboxes: this.inboxesList,
|
||||
labels: this.labels,
|
||||
campaigns: this.campaigns,
|
||||
languages: languages,
|
||||
countries: countries,
|
||||
filterTypes: advancedFilterTypes,
|
||||
allCustomAttributes: this.$store.getters[
|
||||
'attributes/getAttributesByModel'
|
||||
]('conversation_attribute'),
|
||||
};
|
||||
return params;
|
||||
},
|
||||
initializeFolderToFilterModal(activeFolder) {
|
||||
// Here we are setting the params for edit folder modal.
|
||||
// To show the existing values. when we click on edit folder button.
|
||||
|
||||
// Here we get the query from the active folder.
|
||||
// And we are mapping the query to the actual values.
|
||||
// To show in the edit folder modal by the help of generateValuesForEditCustomViews helper.
|
||||
const query = activeFolder?.query?.payload;
|
||||
if (!Array.isArray(query)) return;
|
||||
|
||||
this.appliedFilter.push(
|
||||
...query.map(filter => ({
|
||||
attribute_key: filter.attribute_key,
|
||||
attribute_model: filter.attribute_model,
|
||||
filter_operator: filter.filter_operator,
|
||||
values: Array.isArray(filter.values)
|
||||
? generateValuesForEditCustomViews(
|
||||
filter,
|
||||
this.setParamsForEditFolderModal()
|
||||
)
|
||||
: [],
|
||||
query_operator: filter.query_operator,
|
||||
custom_attribute_type: filter.custom_attribute_type,
|
||||
}))
|
||||
);
|
||||
},
|
||||
getKeyboardListenerParams() {
|
||||
const allConversations = this.$refs.activeConversation.querySelectorAll(
|
||||
'div.conversations-list div.conversation'
|
||||
@@ -667,7 +575,6 @@ export default {
|
||||
}
|
||||
},
|
||||
resetAndFetchData() {
|
||||
this.appliedFilter = [];
|
||||
this.resetBulkActions();
|
||||
this.$store.dispatch('conversationPage/reset');
|
||||
this.$store.dispatch('emptyAllConversations');
|
||||
@@ -680,6 +587,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
this.fetchConversations();
|
||||
this.appliedFilter = [];
|
||||
},
|
||||
fetchConversations() {
|
||||
this.$store
|
||||
@@ -958,43 +866,72 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
@tailwind components;
|
||||
@layer components {
|
||||
.flex-basis-clamp {
|
||||
flex-basis: clamp(20rem, 4vw + 21.25rem, 27.5rem);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.conversations-list-wrap {
|
||||
@apply flex-basis-clamp;
|
||||
@import '~dashboard/assets/scss/woot';
|
||||
|
||||
&.hide {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
&.list--full-width {
|
||||
@apply basis-full;
|
||||
}
|
||||
.spinner {
|
||||
margin-top: var(--space-normal);
|
||||
margin-bottom: var(--space-normal);
|
||||
}
|
||||
|
||||
.conversations-list {
|
||||
@apply overflow-hidden hover:overflow-y-auto;
|
||||
// Prevent the list from scrolling if the submenu is opened
|
||||
&.is-context-menu-open {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
}
|
||||
|
||||
.load-more--button {
|
||||
@apply text-center rounded-none;
|
||||
.conversations-list-wrap {
|
||||
flex-shrink: 0;
|
||||
flex-basis: clamp(32rem, 4vw + 34rem, 44rem);
|
||||
overflow: hidden;
|
||||
|
||||
&.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.list--full-width {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
.page-sub-title {
|
||||
font-size: var(--font-size-two);
|
||||
}
|
||||
}
|
||||
.filter--actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-smaller);
|
||||
}
|
||||
|
||||
.filter__applied {
|
||||
padding-bottom: var(--space-slab) !important;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.tab--chat-type {
|
||||
@apply py-0 px-4;
|
||||
padding: 0 var(--space-normal);
|
||||
|
||||
::v-deep {
|
||||
.tabs {
|
||||
@apply p-0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.conversation--status-pill {
|
||||
background: var(--color-background);
|
||||
border-radius: var(--border-radius-small);
|
||||
color: var(--color-medium-gray);
|
||||
font-size: var(--font-size-micro);
|
||||
font-weight: var(--font-weight-medium);
|
||||
margin: var(--space-micro) var(--space-small) 0;
|
||||
padding: var(--space-smaller);
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.chat-list__title {
|
||||
max-width: 85%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="py-3 px-4">
|
||||
<div class="flex items-center mb-1">
|
||||
<h4 class="text-block-title flex items-center m-0 w-full error">
|
||||
<div class="custom-attribute">
|
||||
<div class="title-wrap">
|
||||
<h4 class="text-block-title title error">
|
||||
<div v-if="isAttributeTypeCheckbox" class="checkbox-wrap">
|
||||
<input
|
||||
v-model="editedValue"
|
||||
@@ -10,7 +10,7 @@
|
||||
@change="onUpdate"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center justify-between w-full">
|
||||
<div class="name-button__wrap">
|
||||
<span
|
||||
class="attribute-name"
|
||||
:class="{ error: $v.editedValue.$error }"
|
||||
@@ -24,7 +24,7 @@
|
||||
size="medium"
|
||||
color-scheme="secondary"
|
||||
icon="delete"
|
||||
class-names="flex justify-end w-4"
|
||||
class-names="delete-button"
|
||||
@click="onDelete"
|
||||
/>
|
||||
</div>
|
||||
@@ -47,10 +47,7 @@
|
||||
<woot-button size="small" icon="checkmark" @click="onUpdate" />
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
v-if="shouldShowErrorMessage"
|
||||
class="text-red-400 dark:text-red-500 text-sm block font-normal -mt-px w-full"
|
||||
>
|
||||
<span v-if="shouldShowErrorMessage" class="error-message">
|
||||
{{ errorMessage }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -64,17 +61,14 @@
|
||||
:href="value"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="value inline-block rounded-sm mb-0 break-all py-0.5 px-1"
|
||||
class="value"
|
||||
>
|
||||
{{ urlValue }}
|
||||
</a>
|
||||
<p
|
||||
v-else
|
||||
class="value inline-block rounded-sm mb-0 break-all py-0.5 px-1"
|
||||
>
|
||||
<p v-else class="value">
|
||||
{{ displayValue || '---' }}
|
||||
</p>
|
||||
<div class="flex max-w-[2rem] gap-1 ml-1 rtl:mr-1 rtl:ml-0">
|
||||
<div class="action-buttons__wrap">
|
||||
<woot-button
|
||||
v-if="showActions"
|
||||
v-tooltip="$t('CUSTOM_ATTRIBUTES.ACTIONS.COPY')"
|
||||
@@ -121,7 +115,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { format, parseISO } from 'date-fns';
|
||||
import format from 'date-fns/format';
|
||||
import { required, url } from 'vuelidate/lib/validators';
|
||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||
import MultiselectDropdown from 'shared/components/ui/MultiselectDropdown.vue';
|
||||
@@ -149,20 +143,15 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
displayValue() {
|
||||
formattedValue() {
|
||||
if (this.isAttributeTypeDate) {
|
||||
return new Date(this.value || new Date()).toLocaleDateString();
|
||||
return format(new Date(this.value || new Date()), DATE_FORMAT);
|
||||
}
|
||||
if (this.isAttributeTypeCheckbox) {
|
||||
return this.value === 'false' ? false : this.value;
|
||||
}
|
||||
return this.value;
|
||||
},
|
||||
formattedValue() {
|
||||
return this.isAttributeTypeDate
|
||||
? format(this.value ? new Date(this.value) : new Date(), DATE_FORMAT)
|
||||
: this.value;
|
||||
},
|
||||
listOptions() {
|
||||
return this.values.map((value, index) => ({
|
||||
id: index + 1,
|
||||
@@ -203,11 +192,17 @@ export default {
|
||||
}
|
||||
return this.$t('CUSTOM_ATTRIBUTES.VALIDATIONS.REQUIRED');
|
||||
},
|
||||
displayValue() {
|
||||
if (this.attributeType === 'date') {
|
||||
return format(new Date(this.editedValue), 'dd-MM-yyyy');
|
||||
}
|
||||
return this.editedValue;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
this.isEditing = false;
|
||||
this.editedValue = this.formattedValue;
|
||||
this.editedValue = this.value;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -254,8 +249,9 @@ export default {
|
||||
onUpdate() {
|
||||
const updatedValue =
|
||||
this.attributeType === 'date'
|
||||
? parseISO(this.editedValue)
|
||||
? format(new Date(this.editedValue), DATE_FORMAT)
|
||||
: this.editedValue;
|
||||
|
||||
this.$v.$touch();
|
||||
if (this.$v.$invalid) {
|
||||
return;
|
||||
@@ -275,45 +271,98 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.custom-attribute {
|
||||
padding: var(--space-slab) var(--space-normal);
|
||||
}
|
||||
|
||||
.title-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-mini);
|
||||
}
|
||||
.title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.checkbox-wrap {
|
||||
@apply flex items-center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.checkbox {
|
||||
@apply my-0 mr-2 ml-0;
|
||||
margin: 0 var(--space-small) 0 0;
|
||||
}
|
||||
.name-button__wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
}
|
||||
.attribute-name {
|
||||
@apply w-full text-slate-800 dark:text-slate-100;
|
||||
width: 100%;
|
||||
&.error {
|
||||
@apply text-red-400 dark:text-red-500;
|
||||
color: var(--r-400);
|
||||
}
|
||||
}
|
||||
|
||||
.title--icon {
|
||||
width: var(--space-two);
|
||||
}
|
||||
.edit-button {
|
||||
@apply hidden;
|
||||
display: none;
|
||||
}
|
||||
.delete-button {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
width: var(--space-normal);
|
||||
}
|
||||
|
||||
.value--view {
|
||||
@apply flex;
|
||||
display: flex;
|
||||
|
||||
&.is-editable:hover {
|
||||
.value {
|
||||
@apply bg-slate-50 dark:bg-slate-700 mb-0;
|
||||
background: var(--color-background);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.edit-button {
|
||||
@apply block;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.action-buttons__wrap {
|
||||
display: flex;
|
||||
max-width: var(--space-larger);
|
||||
}
|
||||
}
|
||||
.value {
|
||||
display: inline-block;
|
||||
min-width: var(--space-mega);
|
||||
border-radius: var(--border-radius-small);
|
||||
margin-bottom: 0;
|
||||
word-break: break-all;
|
||||
padding: var(--space-micro) var(--space-smaller);
|
||||
}
|
||||
.error-message {
|
||||
color: var(--r-400);
|
||||
display: block;
|
||||
font-size: 1.4rem;
|
||||
font-size: var(--font-size-small);
|
||||
font-weight: 400;
|
||||
margin-bottom: 1rem;
|
||||
margin-top: -1.6rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
::v-deep {
|
||||
.selector-wrap {
|
||||
@apply m-0 top-1;
|
||||
margin: 0;
|
||||
top: var(--space-smaller);
|
||||
.selector-name {
|
||||
@apply ml-0;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
.name {
|
||||
@apply ml-0;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<woot-modal-header :header-title="$t('CONVERSATION.CUSTOM_SNOOZE.TITLE')" />
|
||||
<form class="modal-content" @submit.prevent="chooseTime">
|
||||
<date-picker
|
||||
v-model="snoozeTime"
|
||||
type="datetime"
|
||||
inline
|
||||
:lang="lang"
|
||||
:disabled-date="disabledDate"
|
||||
:disabled-time="disabledTime"
|
||||
:popup-style="{ width: '100%' }"
|
||||
/>
|
||||
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full">
|
||||
<woot-button variant="clear" @click.prevent="onClose">
|
||||
{{ this.$t('CONVERSATION.CUSTOM_SNOOZE.CANCEL') }}
|
||||
</woot-button>
|
||||
<woot-button>
|
||||
{{ this.$t('CONVERSATION.CUSTOM_SNOOZE.APPLY') }}
|
||||
</woot-button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DatePicker from 'vue2-datepicker';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DatePicker,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
snoozeTime: null,
|
||||
lang: {
|
||||
days: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
|
||||
yearFormat: 'YYYY',
|
||||
monthFormat: 'MMMM',
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
onClose() {
|
||||
this.$emit('close');
|
||||
},
|
||||
chooseTime() {
|
||||
this.$emit('choose-time', this.snoozeTime);
|
||||
},
|
||||
disabledDate(date) {
|
||||
// Disable all the previous dates
|
||||
const yesterday = new Date();
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
return date < yesterday;
|
||||
},
|
||||
disabledTime(date) {
|
||||
// Allow only time after 1 hour
|
||||
const now = new Date();
|
||||
now.setHours(now.getHours() + 1);
|
||||
return date < now;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.modal-content {
|
||||
@apply pt-2 px-5 pb-6;
|
||||
}
|
||||
</style>
|
||||
@@ -8,7 +8,6 @@
|
||||
>
|
||||
<div :class="modalContainerClassName" @click.stop>
|
||||
<woot-button
|
||||
v-if="showCloseButton"
|
||||
color-scheme="secondary"
|
||||
icon="dismiss"
|
||||
variant="clear"
|
||||
@@ -29,10 +28,6 @@ export default {
|
||||
default: true,
|
||||
},
|
||||
show: Boolean,
|
||||
showCloseButton: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
onClose: {
|
||||
type: Function,
|
||||
required: true,
|
||||
@@ -52,8 +47,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
modalContainerClassName() {
|
||||
let className =
|
||||
'modal-container bg-white dark:bg-slate-800 skip-context-menu';
|
||||
let className = 'modal-container skip-context-menu';
|
||||
if (this.fullWidth) {
|
||||
return `${className} modal-container--full-width`;
|
||||
}
|
||||
@@ -107,7 +101,7 @@ export default {
|
||||
.modal-container {
|
||||
border-radius: 0;
|
||||
height: 100%;
|
||||
width: 30rem;
|
||||
width: 48rem;
|
||||
}
|
||||
}
|
||||
.modal-big {
|
||||
|
||||
@@ -1,22 +1,12 @@
|
||||
<template>
|
||||
<div class="flex flex-col items-start pt-8 px-8 pb-0">
|
||||
<div class="column page-top-bar">
|
||||
<img v-if="headerImage" :src="headerImage" alt="No image" />
|
||||
<h2
|
||||
ref="modalHeaderTitle"
|
||||
class="text-slate-800 text-lg dark:text-slate-100"
|
||||
>
|
||||
<h2 class="page-sub-title">
|
||||
{{ headerTitle }}
|
||||
</h2>
|
||||
<p
|
||||
v-if="headerContent"
|
||||
ref="modalHeaderContent"
|
||||
class="w-full break-words text-slate-600 mt-2 text-sm dark:text-slate-300"
|
||||
>
|
||||
<p v-if="headerContent" class="small-12 column wrap-content">
|
||||
{{ headerContent }}
|
||||
<span
|
||||
v-if="headerContentValue"
|
||||
class="font-semibold text-sm text-slate-600 dark:text-slate-300"
|
||||
>
|
||||
<span v-if="headerContentValue" class="content-value">
|
||||
{{ headerContentValue }}
|
||||
</span>
|
||||
</p>
|
||||
@@ -46,3 +36,13 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.wrap-content {
|
||||
word-wrap: break-word;
|
||||
margin-top: var(--space-small);
|
||||
|
||||
.content-value {
|
||||
font-weight: var(--font-weight-bold);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -77,7 +77,7 @@ export default {
|
||||
@import '~dashboard/assets/scss/mixins';
|
||||
|
||||
.ui-notification-container {
|
||||
max-width: 25rem;
|
||||
max-width: 40rem;
|
||||
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: 15rem;
|
||||
min-width: 24rem;
|
||||
padding: var(--space-normal);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,20 @@
|
||||
<template>
|
||||
<div
|
||||
class="ml-0 mr-0 flex pt-0 pr-4 pb-4 pl-0"
|
||||
:class="{
|
||||
'pt-4 border-b border-solid border-slate-50 dark:border-slate-600': showBorder,
|
||||
}"
|
||||
>
|
||||
<div class="w-[30%] min-w-0 max-w-[30%] pr-12">
|
||||
<p
|
||||
v-if="title"
|
||||
class="text-base text-woot-500 dark:text-woot-500 mb-0 font-medium"
|
||||
>
|
||||
<div class="row settings--section">
|
||||
<div class="medium-4 small-12 title--section">
|
||||
<p class="sub-block-title">
|
||||
{{ title }}
|
||||
</p>
|
||||
<p class="text-sm mb-2">
|
||||
<slot v-if="subTitle" name="subTitle">
|
||||
<p class="sub-head">
|
||||
<slot name="subTitle">
|
||||
{{ subTitle }}
|
||||
</slot>
|
||||
</p>
|
||||
<p v-if="note">
|
||||
<span class="font-semibold">{{ $t('INBOX_MGMT.NOTE') }}</span>
|
||||
<span class="note">{{ $t('INBOX_MGMT.NOTE') }}</span>
|
||||
{{ note }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="w-[50%] min-w-0 max-w-[50%]">
|
||||
<div class="medium-6 small-12">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
@@ -33,15 +25,11 @@ export default {
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
required: true,
|
||||
},
|
||||
subTitle: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
showBorder: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
required: true,
|
||||
},
|
||||
note: {
|
||||
type: String,
|
||||
@@ -50,3 +38,27 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~dashboard/assets/scss/variables';
|
||||
|
||||
.settings--section {
|
||||
border-bottom: 1px solid $color-border;
|
||||
display: flex;
|
||||
padding: $space-normal $space-normal $space-normal 0;
|
||||
|
||||
.sub-block-title {
|
||||
color: $color-woot;
|
||||
font-weight: $font-weight-medium;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.title--section {
|
||||
padding-right: var(--space-large);
|
||||
}
|
||||
|
||||
.note {
|
||||
font-weight: var(--font-weight-bold);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<woot-button
|
||||
:size="size"
|
||||
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>
|
||||
@@ -13,12 +13,6 @@
|
||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
size: {
|
||||
type: String,
|
||||
default: 'small',
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onMenuItemClick() {
|
||||
bus.$emit(BUS_EVENTS.TOGGLE_SIDEMENU);
|
||||
@@ -26,3 +20,8 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.toggle-sidebar {
|
||||
margin-left: var(--space-minus-small);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
<template>
|
||||
<banner
|
||||
v-if="shouldShowBanner"
|
||||
color-scheme="alert"
|
||||
:banner-message="bannerMessage"
|
||||
:action-button-label="actionButtonMessage"
|
||||
has-action-button
|
||||
@click="routeToBilling"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Banner from 'dashboard/components/ui/Banner.vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import adminMixin from 'dashboard/mixins/isAdmin';
|
||||
import accountMixin from 'dashboard/mixins/account';
|
||||
|
||||
const EMPTY_SUBSCRIPTION_INFO = {
|
||||
status: null,
|
||||
endsOn: null,
|
||||
};
|
||||
|
||||
export default {
|
||||
components: { Banner },
|
||||
mixins: [adminMixin, accountMixin],
|
||||
computed: {
|
||||
...mapGetters({
|
||||
isOnChatwootCloud: 'globalConfig/isOnChatwootCloud',
|
||||
getAccount: 'accounts/getAccount',
|
||||
}),
|
||||
bannerMessage() {
|
||||
return this.$t('GENERAL_SETTINGS.PAYMENT_PENDING');
|
||||
},
|
||||
actionButtonMessage() {
|
||||
return this.$t('GENERAL_SETTINGS.OPEN_BILLING');
|
||||
},
|
||||
shouldShowBanner() {
|
||||
if (!this.isOnChatwootCloud) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.isAdmin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.isPaymentPending();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
routeToBilling() {
|
||||
this.$router.push({
|
||||
name: 'billing_settings_index',
|
||||
params: { accountId: this.accountId },
|
||||
});
|
||||
},
|
||||
isPaymentPending() {
|
||||
const { status, endsOn } = this.getSubscriptionInfo();
|
||||
|
||||
if (status && endsOn) {
|
||||
const now = new Date();
|
||||
if (status === 'past_due' && endsOn < now) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
getSubscriptionInfo() {
|
||||
const account = this.getAccount(this.accountId);
|
||||
if (!account) return EMPTY_SUBSCRIPTION_INFO;
|
||||
|
||||
const { custom_attributes: subscription } = account;
|
||||
if (!subscription) return EMPTY_SUBSCRIPTION_INFO;
|
||||
|
||||
const {
|
||||
subscription_status: status,
|
||||
subscription_ends_on: endsOn,
|
||||
} = subscription;
|
||||
|
||||
return { status, endsOn: new Date(endsOn) };
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<banner
|
||||
v-if="shouldShowBanner"
|
||||
class="update-banner"
|
||||
color-scheme="primary"
|
||||
:banner-message="bannerMessage"
|
||||
href-link="https://github.com/chatwoot/chatwoot/releases"
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
<template>
|
||||
<banner
|
||||
v-if="shouldShowBanner"
|
||||
color-scheme="alert"
|
||||
:banner-message="bannerMessage"
|
||||
:action-button-label="actionButtonMessage"
|
||||
has-action-button
|
||||
@click="routeToBilling"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Banner from 'dashboard/components/ui/Banner.vue';
|
||||
import { mapGetters } from 'vuex';
|
||||
import adminMixin from 'dashboard/mixins/isAdmin';
|
||||
import accountMixin from 'dashboard/mixins/account';
|
||||
import { differenceInDays } from 'date-fns';
|
||||
|
||||
export default {
|
||||
components: { Banner },
|
||||
mixins: [adminMixin, accountMixin],
|
||||
data() {
|
||||
return { conversationMeta: {} };
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
isOnChatwootCloud: 'globalConfig/isOnChatwootCloud',
|
||||
getAccount: 'accounts/getAccount',
|
||||
}),
|
||||
bannerMessage() {
|
||||
return this.$t('GENERAL_SETTINGS.LIMITS_UPGRADE');
|
||||
},
|
||||
actionButtonMessage() {
|
||||
return this.$t('GENERAL_SETTINGS.OPEN_BILLING');
|
||||
},
|
||||
shouldShowBanner() {
|
||||
if (!this.isOnChatwootCloud) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isTrialAccount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.isLimitExceeded();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.isOnChatwootCloud) {
|
||||
this.fetchLimits();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchLimits() {
|
||||
this.$store.dispatch('accounts/limits');
|
||||
},
|
||||
routeToBilling() {
|
||||
this.$router.push({
|
||||
name: 'billing_settings_index',
|
||||
params: { accountId: this.accountId },
|
||||
});
|
||||
},
|
||||
isTrialAccount() {
|
||||
// check if account is less than 15 days old
|
||||
const account = this.getAccount(this.accountId);
|
||||
if (!account) return false;
|
||||
|
||||
const createdAt = new Date(account.created_at);
|
||||
|
||||
const diffDays = differenceInDays(new Date(), createdAt);
|
||||
|
||||
return diffDays <= 15;
|
||||
},
|
||||
isLimitExceeded() {
|
||||
const account = this.getAccount(this.accountId);
|
||||
if (!account) return false;
|
||||
|
||||
const { limits } = account;
|
||||
if (!limits) return false;
|
||||
|
||||
const { conversation, non_web_inboxes: nonWebInboxes } = limits;
|
||||
return this.testLimit(conversation) || this.testLimit(nonWebInboxes);
|
||||
},
|
||||
testLimit({ allowed, consumed }) {
|
||||
return consumed > allowed;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,11 +0,0 @@
|
||||
<template>
|
||||
<kbd class="hotkey">
|
||||
<slot />
|
||||
</kbd>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
kbd.hotkey {
|
||||
@apply inline-flex p-0.5 leading-[0.625rem] min-w-[1rem] tracking-wide uppercase text-slate-800 dark:text-slate-100 bg-slate-50 dark:bg-slate-600 text-xxs border border-solid border-slate-75 dark:border-slate-600 rounded flex-shrink-0 items-center select-none justify-center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="resolve-actions relative flex items-center justify-end">
|
||||
<div class="resolve-actions">
|
||||
<div class="button-group">
|
||||
<woot-button
|
||||
v-if="isOpen"
|
||||
@@ -49,17 +49,6 @@
|
||||
class="dropdown-pane dropdown-pane--open"
|
||||
>
|
||||
<woot-dropdown-menu>
|
||||
<woot-dropdown-item v-if="!isPending">
|
||||
<woot-button
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
size="small"
|
||||
icon="snooze"
|
||||
@click="() => openSnoozeModal()"
|
||||
>
|
||||
{{ this.$t('CONVERSATION.RESOLVE_DROPDOWN.SNOOZE_UNTIL') }}
|
||||
</woot-button>
|
||||
</woot-dropdown-item>
|
||||
<woot-dropdown-item v-if="!isPending">
|
||||
<woot-button
|
||||
variant="clear"
|
||||
@@ -71,35 +60,71 @@
|
||||
{{ this.$t('CONVERSATION.RESOLVE_DROPDOWN.MARK_PENDING') }}
|
||||
</woot-button>
|
||||
</woot-dropdown-item>
|
||||
|
||||
<woot-dropdown-divider v-if="isOpen" />
|
||||
<woot-dropdown-sub-menu
|
||||
v-if="isOpen"
|
||||
:title="this.$t('CONVERSATION.RESOLVE_DROPDOWN.SNOOZE.TITLE')"
|
||||
>
|
||||
<woot-dropdown-item>
|
||||
<woot-button
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
size="small"
|
||||
icon="send-clock"
|
||||
@click="() => toggleStatus(STATUS_TYPE.SNOOZED, null)"
|
||||
>
|
||||
{{ this.$t('CONVERSATION.RESOLVE_DROPDOWN.SNOOZE.NEXT_REPLY') }}
|
||||
</woot-button>
|
||||
</woot-dropdown-item>
|
||||
<woot-dropdown-item>
|
||||
<woot-button
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
size="small"
|
||||
icon="dual-screen-clock"
|
||||
@click="
|
||||
() => toggleStatus(STATUS_TYPE.SNOOZED, snoozeTimes.tomorrow)
|
||||
"
|
||||
>
|
||||
{{ this.$t('CONVERSATION.RESOLVE_DROPDOWN.SNOOZE.TOMORROW') }}
|
||||
</woot-button>
|
||||
</woot-dropdown-item>
|
||||
<woot-dropdown-item>
|
||||
<woot-button
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
size="small"
|
||||
icon="calendar-clock"
|
||||
@click="
|
||||
() => toggleStatus(STATUS_TYPE.SNOOZED, snoozeTimes.nextWeek)
|
||||
"
|
||||
>
|
||||
{{ this.$t('CONVERSATION.RESOLVE_DROPDOWN.SNOOZE.NEXT_WEEK') }}
|
||||
</woot-button>
|
||||
</woot-dropdown-item>
|
||||
</woot-dropdown-sub-menu>
|
||||
</woot-dropdown-menu>
|
||||
</div>
|
||||
<woot-modal
|
||||
:show.sync="showCustomSnoozeModal"
|
||||
:on-close="hideCustomSnoozeModal"
|
||||
>
|
||||
<custom-snooze-modal
|
||||
@close="hideCustomSnoozeModal"
|
||||
@choose-time="chooseSnoozeTime"
|
||||
/>
|
||||
</woot-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getUnixTime } from 'date-fns';
|
||||
import { mapGetters } from 'vuex';
|
||||
import { mixin as clickaway } from 'vue-clickaway';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import CustomSnoozeModal from 'dashboard/components/CustomSnoozeModal';
|
||||
import snoozeTimesMixin from 'dashboard/mixins/conversation/snoozeTimesMixin.js';
|
||||
import eventListenerMixins from 'shared/mixins/eventListenerMixins';
|
||||
import {
|
||||
hasPressedAltAndEKey,
|
||||
hasPressedCommandPlusAltAndEKey,
|
||||
hasPressedAltAndMKey,
|
||||
} from 'shared/helpers/KeyboardHelpers';
|
||||
import { findSnoozeTime } from 'dashboard/helper/snoozeHelpers';
|
||||
|
||||
import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
|
||||
import WootDropdownSubMenu from 'shared/components/ui/dropdown/DropdownSubMenu.vue';
|
||||
import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
|
||||
import WootDropdownDivider from 'shared/components/ui/dropdown/DropdownDivider';
|
||||
|
||||
import wootConstants from 'dashboard/constants/globals';
|
||||
import {
|
||||
@@ -112,16 +137,16 @@ export default {
|
||||
components: {
|
||||
WootDropdownItem,
|
||||
WootDropdownMenu,
|
||||
CustomSnoozeModal,
|
||||
WootDropdownSubMenu,
|
||||
WootDropdownDivider,
|
||||
},
|
||||
mixins: [clickaway, alertMixin, eventListenerMixins],
|
||||
mixins: [clickaway, alertMixin, eventListenerMixins, snoozeTimesMixin],
|
||||
props: { conversationId: { type: [String, Number], required: true } },
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
showActionsDropdown: false,
|
||||
STATUS_TYPE: wootConstants.STATUS_TYPE,
|
||||
showCustomSnoozeModal: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -193,26 +218,10 @@ export default {
|
||||
}
|
||||
},
|
||||
onCmdSnoozeConversation(snoozeType) {
|
||||
if (snoozeType === wootConstants.SNOOZE_OPTIONS.UNTIL_CUSTOM_TIME) {
|
||||
this.showCustomSnoozeModal = true;
|
||||
} else {
|
||||
this.toggleStatus(
|
||||
this.STATUS_TYPE.SNOOZED,
|
||||
findSnoozeTime(snoozeType) || null
|
||||
);
|
||||
}
|
||||
},
|
||||
chooseSnoozeTime(customSnoozeTime) {
|
||||
this.showCustomSnoozeModal = false;
|
||||
if (customSnoozeTime) {
|
||||
this.toggleStatus(
|
||||
this.STATUS_TYPE.SNOOZED,
|
||||
getUnixTime(customSnoozeTime)
|
||||
);
|
||||
}
|
||||
},
|
||||
hideCustomSnoozeModal() {
|
||||
this.showCustomSnoozeModal = false;
|
||||
this.toggleStatus(
|
||||
this.STATUS_TYPE.SNOOZED,
|
||||
this.snoozeTimes[snoozeType] || null
|
||||
);
|
||||
},
|
||||
onCmdOpenConversation() {
|
||||
this.toggleStatus(this.STATUS_TYPE.OPEN);
|
||||
@@ -243,19 +252,23 @@ export default {
|
||||
this.isLoading = false;
|
||||
});
|
||||
},
|
||||
openSnoozeModal() {
|
||||
const ninja = document.querySelector('ninja-keys');
|
||||
ninja.open({ parent: 'snooze_conversation' });
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.dropdown-pane {
|
||||
@apply left-auto top-[2.625rem] mt-0.5 right-0 max-w-[12.5rem] min-w-[9.75rem];
|
||||
.resolve-actions {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.dropdown-menu__item {
|
||||
@apply mb-0;
|
||||
}
|
||||
.dropdown-pane {
|
||||
left: unset;
|
||||
top: 4.2rem;
|
||||
margin-top: var(--space-micro);
|
||||
right: 0;
|
||||
max-width: 20rem;
|
||||
min-width: 15.6rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<woot-dropdown-item
|
||||
v-for="status in availabilityStatuses"
|
||||
:key="status.value"
|
||||
class="flex items-baseline"
|
||||
class="status-items"
|
||||
>
|
||||
<woot-button
|
||||
size="small"
|
||||
@@ -18,25 +18,23 @@
|
||||
</woot-button>
|
||||
</woot-dropdown-item>
|
||||
<woot-dropdown-divider />
|
||||
<woot-dropdown-item class="m-0 flex items-center justify-between p-2">
|
||||
<div class="flex items-center">
|
||||
<woot-dropdown-item class="auto-offline--toggle">
|
||||
<div class="info-wrap">
|
||||
<fluent-icon
|
||||
v-tooltip.right-start="$t('SIDEBAR.SET_AUTO_OFFLINE.INFO_TEXT')"
|
||||
icon="info"
|
||||
size="14"
|
||||
class="mt-px"
|
||||
class="info-icon"
|
||||
/>
|
||||
|
||||
<span
|
||||
class="my-0 mx-1 text-xs font-medium text-slate-600 dark:text-slate-100"
|
||||
>
|
||||
<span class="auto-offline--text">
|
||||
{{ $t('SIDEBAR.SET_AUTO_OFFLINE.TEXT') }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<woot-switch
|
||||
size="small"
|
||||
class="mt-px mx-1 mb-0"
|
||||
class="auto-offline--switch"
|
||||
:value="currentUserAutoOffline"
|
||||
@input="updateAutoOffline"
|
||||
/>
|
||||
@@ -140,3 +138,71 @@ 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="h-full flex">
|
||||
<aside class="woot-sidebar">
|
||||
<primary-sidebar
|
||||
:logo-source="globalConfig.logoThumbnail"
|
||||
:installation-name="globalConfig.installationName"
|
||||
@@ -11,21 +11,22 @@
|
||||
@key-shortcut-modal="toggleKeyShortcutModal"
|
||||
@open-notification-panel="openNotificationPanel"
|
||||
/>
|
||||
|
||||
<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 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>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
@@ -213,3 +214,87 @@ 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,29 +1,25 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="showShowCurrentAccountContext"
|
||||
class="rounded-md text-xs py-2 px-2 mt-2 relative border border-slate-50 dark:border-slate-800/50 hover:bg-slate-50 dark:hover:bg-slate-700 cursor-pointer"
|
||||
class="account-context--group"
|
||||
@mouseover="setShowSwitch"
|
||||
@mouseleave="resetShowSwitch"
|
||||
>
|
||||
{{ $t('SIDEBAR.CURRENTLY_VIEWING_ACCOUNT') }}
|
||||
<p class="text-ellipsis font-medium mb-0">
|
||||
<p class="account-context--name text-ellipsis">
|
||||
{{ account.name }}
|
||||
</p>
|
||||
<transition name="fade">
|
||||
<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 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>
|
||||
</transition>
|
||||
</div>
|
||||
@@ -55,6 +51,51 @@ 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,39 +2,31 @@
|
||||
<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="px-8 pt-4 pb-8">
|
||||
<div class="account-selector--wrap">
|
||||
<div
|
||||
v-for="account in currentUser.accounts"
|
||||
:id="`account-${account.id}`"
|
||||
:key="account.id"
|
||||
class="pt-0 pb-0"
|
||||
class="account-selector"
|
||||
>
|
||||
<button
|
||||
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"
|
||||
class="button expanded clear link"
|
||||
@click="onChangeAccount(account.id)"
|
||||
>
|
||||
<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>
|
||||
<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>
|
||||
</label>
|
||||
</span>
|
||||
<fluent-icon
|
||||
v-show="account.id === accountId"
|
||||
class="text-slate-800 dark:text-slate-100"
|
||||
class="selected--account"
|
||||
icon="checkmark-circle"
|
||||
type="solid"
|
||||
size="24"
|
||||
@@ -82,3 +74,32 @@ 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>
|
||||
|
||||
@@ -2,23 +2,24 @@
|
||||
<woot-modal
|
||||
:show="show"
|
||||
:on-close="() => $emit('close-account-create-modal')"
|
||||
class="account-selector--modal"
|
||||
>
|
||||
<div class="h-auto overflow-auto flex flex-col">
|
||||
<div class="column content-box">
|
||||
<woot-modal-header
|
||||
:header-title="$t('CREATE_ACCOUNT.NEW_ACCOUNT')"
|
||||
:header-content="$t('CREATE_ACCOUNT.SELECTOR_SUBTITLE')"
|
||||
/>
|
||||
<div v-if="!hasAccounts" class="text-sm mt-6 mx-8 mb-0">
|
||||
<div class="items-center rounded-md flex alert">
|
||||
<div class="ml-1 mr-3">
|
||||
<div v-if="!hasAccounts" class="alert-wrap">
|
||||
<div class="callout alert">
|
||||
<div class="icon-wrap">
|
||||
<fluent-icon icon="warning" />
|
||||
</div>
|
||||
{{ $t('CREATE_ACCOUNT.NO_ACCOUNT_WARNING') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form class="flex flex-col w-full" @submit.prevent="addAccount">
|
||||
<div class="w-full">
|
||||
<form class="row" @submit.prevent="addAccount">
|
||||
<div class="medium-12 columns">
|
||||
<label :class="{ error: $v.accountName.$error }">
|
||||
{{ $t('CREATE_ACCOUNT.FORM.NAME.LABEL') }}
|
||||
<input
|
||||
@@ -29,8 +30,8 @@
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<div class="w-full">
|
||||
<div class="modal-footer medium-12 columns">
|
||||
<div class="medium-12 columns">
|
||||
<woot-submit-button
|
||||
:disabled="
|
||||
$v.accountName.$invalid ||
|
||||
@@ -101,3 +102,20 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.alert-wrap {
|
||||
font-size: var(--font-size-small);
|
||||
margin: var(--space-medium) var(--space-large) var(--space-zero);
|
||||
|
||||
.callout {
|
||||
align-items: center;
|
||||
border-radius: var(--border-radius-normal);
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-wrap {
|
||||
margin-left: var(--space-smaller);
|
||||
margin-right: var(--space-slab);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="w-8 h-8">
|
||||
<div class="logo">
|
||||
<router-link :to="dashboardPath" replace>
|
||||
<img :src="source" :alt="name" />
|
||||
</router-link>
|
||||
@@ -30,3 +30,17 @@ 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,25 +1,15 @@
|
||||
<template>
|
||||
<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,
|
||||
}"
|
||||
<div class="notifications-link">
|
||||
<woot-button
|
||||
class-names="notifications-link--button"
|
||||
variant="clear"
|
||||
color-scheme="secondary"
|
||||
:class="{ 'is-active': isNotificationPanelActive }"
|
||||
@click="openNotificationPanel"
|
||||
>
|
||||
<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>
|
||||
<fluent-icon icon="alert" />
|
||||
<span v-if="unreadCount" class="badge warning">{{ unreadCount }}</span>
|
||||
</woot-button>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -53,3 +43,37 @@ 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,10 +3,11 @@
|
||||
<div
|
||||
v-if="show"
|
||||
v-on-clickaway="onClickAway"
|
||||
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 }"
|
||||
class="options-menu dropdown-pane"
|
||||
:class="{ 'dropdown-pane--open': show }"
|
||||
>
|
||||
<availability-status />
|
||||
<li class="divider" />
|
||||
<woot-dropdown-menu>
|
||||
<woot-dropdown-item v-if="showChangeAccountOption">
|
||||
<woot-button
|
||||
@@ -49,7 +50,7 @@
|
||||
>
|
||||
<a
|
||||
:href="href"
|
||||
class="button small clear secondary bg-white dark:bg-slate-800 h-8"
|
||||
class="button small clear secondary"
|
||||
:class="{ 'is-active': isActive }"
|
||||
@click="e => handleProfileSettingClick(e, navigate)"
|
||||
>
|
||||
@@ -63,7 +64,7 @@
|
||||
<woot-dropdown-item v-if="currentUser.type === 'SuperAdmin'">
|
||||
<a
|
||||
href="/super_admin"
|
||||
class="button small clear secondary bg-white dark:bg-slate-800 h-8"
|
||||
class="button small clear secondary"
|
||||
target="_blank"
|
||||
rel="noopener nofollow noreferrer"
|
||||
@click="$emit('close')"
|
||||
@@ -148,3 +149,12 @@ 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,14 +1,11 @@
|
||||
<template>
|
||||
<div
|
||||
class="h-full w-16 bg-white dark:bg-slate-900 border-r border-slate-50 dark:border-slate-800/50 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"
|
||||
/>
|
||||
<div class="primary--sidebar">
|
||||
<logo
|
||||
:source="logoSource"
|
||||
:name="installationName"
|
||||
:account-id="accountId"
|
||||
/>
|
||||
<nav class="menu vertical">
|
||||
<primary-nav-item
|
||||
v-for="menuItem in menuItems"
|
||||
:key="menuItem.toState"
|
||||
@@ -17,8 +14,8 @@
|
||||
:to="menuItem.toState"
|
||||
:is-child-menu-active="menuItem.key === activeMenuItem"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col items-center justify-end pb-6">
|
||||
</nav>
|
||||
<div class="menu vertical user-menu">
|
||||
<primary-nav-item
|
||||
v-if="!isACustomBrandedInstance"
|
||||
icon="book-open-globe"
|
||||
@@ -104,3 +101,27 @@ 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>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user