diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..3de57a360 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +node_modules/ +dist/ +logs/ +.DS_Store +.git/ +config/local.json +pleroma-backend/ +test/e2e/reports/ +test/e2e-playwright/test-results/ +test/e2e-playwright/playwright-report/ +__screenshots__/ + diff --git a/.gitignore b/.gitignore index 01ffda9a8..c4a96ee1e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,11 @@ dist/ npm-debug.log test/unit/coverage test/e2e/reports +test/e2e-playwright/test-results +test/e2e-playwright/playwright-report selenium-debug.log .idea/ +.gitlab-ci-local/ config/local.json src/assets/emoji.json logs/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b711c7fc9..06fbf45f9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -71,6 +71,135 @@ test: - test/**/__screenshots__ when: on_failure +e2e-pleroma: + stage: test + image: mcr.microsoft.com/playwright:v1.57.0-jammy + services: + - name: postgres:15-alpine + alias: db + - name: $PLEROMA_IMAGE + alias: pleroma + entrypoint: ["/bin/ash", "-c"] + command: + - | + set -eu + + SEED_SENTINEL_PATH=/var/lib/pleroma/.e2e_seeded + CONFIG_OVERRIDE_PATH=/var/lib/pleroma/config.exs + + echo '-- Waiting for database...' + while ! pg_isready -U ${DB_USER:-pleroma} -d postgres://${DB_HOST:-db}:${DB_PORT:-5432}/${DB_NAME:-pleroma} -t 1; do + sleep 1s + done + + echo '-- Writing E2E config overrides...' + cat > $CONFIG_OVERRIDE_PATH </dev/null; then + kill -TERM $PLEROMA_PID + wait $PLEROMA_PID || true + fi + } + + trap cleanup INT TERM + + echo '-- Waiting for API...' + api_ok=false + for _i in $(seq 1 120); do + if wget -qO- http://127.0.0.1:4000/api/v1/instance >/dev/null 2>&1; then + api_ok=true + break + fi + sleep 1s + done + + if [ $api_ok != true ]; then + echo 'Timed out waiting for Pleroma API to become available' + exit 1 + fi + + if [ ! -f $SEED_SENTINEL_PATH ]; then + if [ -n ${E2E_ADMIN_USERNAME:-} ] && [ -n ${E2E_ADMIN_PASSWORD:-} ] && [ -n ${E2E_ADMIN_EMAIL:-} ]; then + echo '-- Seeding admin user' $E2E_ADMIN_USERNAME '...' + if ! /opt/pleroma/bin/pleroma_ctl user new $E2E_ADMIN_USERNAME $E2E_ADMIN_EMAIL --admin --password $E2E_ADMIN_PASSWORD -y; then + echo '-- User already exists or creation failed, ensuring admin + confirmed...' + /opt/pleroma/bin/pleroma_ctl user set $E2E_ADMIN_USERNAME --admin --confirmed + fi + else + echo '-- Skipping admin seeding (missing E2E_ADMIN_* env)' + fi + + touch $SEED_SENTINEL_PATH + fi + + wait $PLEROMA_PID + tags: + - amd64 + - himem + variables: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1" + FF_NETWORK_PER_BUILD: "true" + PLEROMA_IMAGE: git.pleroma.social:5050/pleroma/pleroma:stable + POSTGRES_USER: pleroma + POSTGRES_PASSWORD: pleroma + POSTGRES_DB: pleroma + DB_USER: pleroma + DB_PASS: pleroma + DB_NAME: pleroma + DB_HOST: db + DB_PORT: 5432 + DOMAIN: localhost + INSTANCE_NAME: Pleroma E2E + E2E_ADMIN_USERNAME: admin + E2E_ADMIN_PASSWORD: adminadmin + E2E_ADMIN_EMAIL: admin@example.com + ADMIN_EMAIL: $E2E_ADMIN_EMAIL + NOTIFY_EMAIL: $E2E_ADMIN_EMAIL + VITE_PROXY_TARGET: http://pleroma:4000 + VITE_PROXY_ORIGIN: http://localhost:4000 + E2E_BASE_URL: http://localhost:8080 + script: + - npm install -g yarn@1.22.22 + - yarn --frozen-lockfile + - | + echo "-- Waiting for Pleroma API..." + api_ok="false" + for _i in $(seq 1 120); do + if wget -qO- http://pleroma:4000/api/v1/instance >/dev/null 2>&1; then + api_ok="true" + break + fi + sleep 1s + done + if [ "$api_ok" != "true" ]; then + echo "Timed out waiting for Pleroma API to become available" + exit 1 + fi + - yarn e2e:pw + artifacts: + when: on_failure + paths: + - test/e2e-playwright/test-results + - test/e2e-playwright/playwright-report + build: stage: build tags: diff --git a/biome.json b/biome.json index 9b4ee2663..d64639d52 100644 --- a/biome.json +++ b/biome.json @@ -124,6 +124,22 @@ ], "assist": { "enabled": true, - "actions": { "source": { "organizeImports": "on" } } + "actions": { + "source": { + "organizeImports": { + "level": "on", + "options": { + "groups": [ + [":NODE:", ":PACKAGE:", "!src/**", "!@fortawesome/**"], + ":BLANK_LINE:", + [":PATH:", "src/**"], + ":BLANK_LINE:", + "@fortawesome/fontawesome-svg-core", + "@fortawesome/*" + ] + } + } + } + } } } diff --git a/build/emojis_plugin.js b/build/emojis_plugin.js index 43a665e50..7979086dd 100644 --- a/build/emojis_plugin.js +++ b/build/emojis_plugin.js @@ -1,5 +1,6 @@ import { access } from 'node:fs/promises' import { resolve } from 'node:path' + import { languages } from '../src/i18n/languages.js' const annotationsImportPrefix = '@kazvmoe-infra/unicode-emoji-json/annotations/' diff --git a/build/service_worker_messages.js b/build/service_worker_messages.js index 0ebd2b471..0948aa919 100644 --- a/build/service_worker_messages.js +++ b/build/service_worker_messages.js @@ -1,6 +1,7 @@ import { readFile } from 'node:fs/promises' import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' + import { langCodeToJsonName, languages } from '../src/i18n/languages.js' const i18nDir = resolve( diff --git a/build/sw_plugin.js b/build/sw_plugin.js index 88520ba31..03c5978d7 100644 --- a/build/sw_plugin.js +++ b/build/sw_plugin.js @@ -3,6 +3,7 @@ import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import * as esbuild from 'esbuild' import { build } from 'vite' + import { generateServiceWorkerMessages, i18nFiles, diff --git a/changelog.d/actor-type.fix b/changelog.d/actor-type.fix new file mode 100644 index 000000000..a2c873c1a --- /dev/null +++ b/changelog.d/actor-type.fix @@ -0,0 +1 @@ +fixed being unable to set actor type from profile page diff --git a/changelog.d/e2e-tests.add b/changelog.d/e2e-tests.add new file mode 100644 index 000000000..ba62b25ac --- /dev/null +++ b/changelog.d/e2e-tests.add @@ -0,0 +1 @@ +Add playwright E2E-tests with an optional docker-based backend diff --git a/changelog.d/e2e.skip b/changelog.d/e2e.skip new file mode 100644 index 000000000..e84c25121 --- /dev/null +++ b/changelog.d/e2e.skip @@ -0,0 +1 @@ +fix e2e diff --git a/docker-compose.e2e.yml b/docker-compose.e2e.yml new file mode 100644 index 000000000..75a4979a1 --- /dev/null +++ b/docker-compose.e2e.yml @@ -0,0 +1,57 @@ +services: + db: + image: postgres:15-alpine + environment: + POSTGRES_USER: pleroma + POSTGRES_PASSWORD: pleroma + POSTGRES_DB: pleroma + healthcheck: + test: ["CMD-SHELL", "pg_isready -U pleroma -d pleroma"] + interval: 2s + timeout: 2s + retries: 30 + + pleroma: + image: ${PLEROMA_IMAGE:-git.pleroma.social:5050/pleroma/pleroma:stable} + environment: + DB_USER: pleroma + DB_PASS: pleroma + DB_NAME: pleroma + DB_HOST: db + DB_PORT: 5432 + DOMAIN: localhost + INSTANCE_NAME: Pleroma E2E + ADMIN_EMAIL: ${E2E_ADMIN_EMAIL:-admin@example.com} + NOTIFY_EMAIL: ${E2E_ADMIN_EMAIL:-admin@example.com} + E2E_ADMIN_USERNAME: ${E2E_ADMIN_USERNAME:-admin} + E2E_ADMIN_PASSWORD: ${E2E_ADMIN_PASSWORD:-adminadmin} + E2E_ADMIN_EMAIL: ${E2E_ADMIN_EMAIL:-admin@example.com} + depends_on: + db: + condition: service_healthy + volumes: + - ./docker/pleroma/entrypoint.e2e.sh:/opt/pleroma/entrypoint.e2e.sh:ro + entrypoint: ["/bin/ash", "/opt/pleroma/entrypoint.e2e.sh"] + healthcheck: + # NOTE: "localhost" may resolve to ::1 in some images (IPv6) while Pleroma only + # listens on IPv4 in this container. Use 127.0.0.1 to avoid false negatives. + test: ["CMD-SHELL", "test -f /var/lib/pleroma/.e2e_seeded && wget -qO- http://127.0.0.1:4000/api/v1/instance >/dev/null || exit 1"] + interval: 5s + timeout: 3s + retries: 60 + + e2e: + build: + context: . + dockerfile: docker/e2e/Dockerfile.e2e + depends_on: + pleroma: + condition: service_healthy + environment: + CI: "1" + VITE_PROXY_TARGET: http://pleroma:4000 + VITE_PROXY_ORIGIN: http://localhost:4000 + E2E_BASE_URL: http://localhost:8080 + E2E_ADMIN_USERNAME: ${E2E_ADMIN_USERNAME:-admin} + E2E_ADMIN_PASSWORD: ${E2E_ADMIN_PASSWORD:-adminadmin} + command: ["yarn", "e2e:pw"] diff --git a/docker/e2e/Dockerfile.e2e b/docker/e2e/Dockerfile.e2e new file mode 100644 index 000000000..e84359ceb --- /dev/null +++ b/docker/e2e/Dockerfile.e2e @@ -0,0 +1,16 @@ +FROM mcr.microsoft.com/playwright:v1.57.0-jammy + +WORKDIR /app + +ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 + +RUN npm install -g yarn@1.22.22 + +COPY package.json yarn.lock ./ +RUN yarn --frozen-lockfile + +COPY . . + +ENV CI=1 + +CMD ["yarn", "e2e:pw"] diff --git a/docker/pleroma/entrypoint.e2e.sh b/docker/pleroma/entrypoint.e2e.sh new file mode 100644 index 000000000..96920eeae --- /dev/null +++ b/docker/pleroma/entrypoint.e2e.sh @@ -0,0 +1,71 @@ +#!/bin/ash + +set -eu + +SEED_SENTINEL_PATH="/var/lib/pleroma/.e2e_seeded" +CONFIG_OVERRIDE_PATH="/var/lib/pleroma/config.exs" + +echo "-- Waiting for database..." +while ! pg_isready -U "${DB_USER:-pleroma}" -d "postgres://${DB_HOST:-db}:${DB_PORT:-5432}/${DB_NAME:-pleroma}" -t 1; do + sleep 1s +done + +echo "-- Writing E2E config overrides..." +cat > "$CONFIG_OVERRIDE_PATH" <<'EOF' +import Config + +config :pleroma, Pleroma.Captcha, + enabled: false + +config :pleroma, :instance, + registrations_open: true, + account_activation_required: false, + approval_required: false +EOF + +echo "-- Running migrations..." +/opt/pleroma/bin/pleroma_ctl migrate + +echo "-- Starting!" +/opt/pleroma/bin/pleroma start & +PLEROMA_PID="$!" + +cleanup() { + if [ -n "${PLEROMA_PID:-}" ] && kill -0 "$PLEROMA_PID" 2>/dev/null; then + kill -TERM "$PLEROMA_PID" + wait "$PLEROMA_PID" || true + fi +} + +trap cleanup INT TERM + +echo "-- Waiting for API..." +api_ok="false" +for _i in $(seq 1 120); do + if wget -qO- http://127.0.0.1:4000/api/v1/instance >/dev/null 2>&1; then + api_ok="true" + break + fi + sleep 1s +done + +if [ "$api_ok" != "true" ]; then + echo "Timed out waiting for Pleroma API to become available" + exit 1 +fi + +if [ ! -f "$SEED_SENTINEL_PATH" ]; then + if [ -n "${E2E_ADMIN_USERNAME:-}" ] && [ -n "${E2E_ADMIN_PASSWORD:-}" ] && [ -n "${E2E_ADMIN_EMAIL:-}" ]; then + echo "-- Seeding admin user (${E2E_ADMIN_USERNAME})..." + if ! /opt/pleroma/bin/pleroma_ctl user new "$E2E_ADMIN_USERNAME" "$E2E_ADMIN_EMAIL" --admin --password "$E2E_ADMIN_PASSWORD" -y; then + echo "-- User already exists (or creation failed), ensuring admin + confirmed..." + /opt/pleroma/bin/pleroma_ctl user set "$E2E_ADMIN_USERNAME" --admin --confirmed + fi + else + echo "-- Skipping admin seeding (missing E2E_ADMIN_* env)" + fi + + touch "$SEED_SENTINEL_PATH" +fi + +wait "$PLEROMA_PID" diff --git a/package.json b/package.json index 33a1d719f..b00ed545a 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "unit": "node build/update-emoji.js && vitest --run", "unit-ci": "node build/update-emoji.js && vitest --run --browser.headless", "unit:watch": "node build/update-emoji.js && vitest", - "e2e": "node test/e2e/runner.js", + "e2e:pw": "playwright test --config test/e2e-playwright/playwright.config.mjs", + "e2e": "sh ./tools/e2e/run.sh", "test": "yarn run unit && yarn run e2e", "ci-biome": "yarn exec biome check", "ci-eslint": "yarn exec eslint", diff --git a/src/App.js b/src/App.js index 83e7f8ee5..33645c63d 100644 --- a/src/App.js +++ b/src/App.js @@ -1,6 +1,7 @@ import { throttle } from 'lodash' import { defineAsyncComponent } from 'vue' import { mapGetters } from 'vuex' + import DesktopNav from './components/desktop_nav/desktop_nav.vue' import EditStatusModal from './components/edit_status_modal/edit_status_modal.vue' import FeaturesPanel from './components/features_panel/features_panel.vue' diff --git a/src/boot/routes.js b/src/boot/routes.js index c601531a9..3296755a1 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -26,6 +26,7 @@ import ShoutPanel from 'components/shout_panel/shout_panel.vue' import TagTimeline from 'components/tag_timeline/tag_timeline.vue' import UserProfile from 'components/user_profile/user_profile.vue' import WhoToFollow from 'components/who_to_follow/who_to_follow.vue' + import NavPanel from 'src/components/nav_panel/nav_panel.vue' import BookmarkFolderEdit from '../components/bookmark_folder_edit/bookmark_folder_edit.vue' import BookmarkFolders from '../components/bookmark_folders/bookmark_folders.vue' diff --git a/src/components/account_actions/account_actions.js b/src/components/account_actions/account_actions.js index 184c2b623..ee94dc544 100644 --- a/src/components/account_actions/account_actions.js +++ b/src/components/account_actions/account_actions.js @@ -1,13 +1,15 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faEllipsisV } from '@fortawesome/free-solid-svg-icons' +import { mapState } from 'vuex' + import UserListMenu from 'src/components/user_list_menu/user_list_menu.vue' import UserTimedFilterModal from 'src/components/user_timed_filter_modal/user_timed_filter_modal.vue' import { useReportsStore } from 'src/stores/reports' -import { mapState } from 'vuex' import ConfirmModal from '../confirm_modal/confirm_modal.vue' import Popover from '../popover/popover.vue' import ProgressButton from '../progress_button/progress_button.vue' +import { library } from '@fortawesome/fontawesome-svg-core' +import { faEllipsisV } from '@fortawesome/free-solid-svg-icons' + library.add(faEllipsisV) const AccountActions = { diff --git a/src/components/announcement/announcement.js b/src/components/announcement/announcement.js index 356852cff..906b84ce2 100644 --- a/src/components/announcement/announcement.js +++ b/src/components/announcement/announcement.js @@ -1,5 +1,6 @@ -import { useAnnouncementsStore } from 'src/stores/announcements' import { mapState } from 'vuex' + +import { useAnnouncementsStore } from 'src/stores/announcements' import localeService from '../../services/locale/locale.service.js' import AnnouncementEditor from '../announcement_editor/announcement_editor.vue' import RichContent from '../rich_content/rich_content.jsx' diff --git a/src/components/announcements_page/announcements_page.js b/src/components/announcements_page/announcements_page.js index d3429613c..0c4383d2e 100644 --- a/src/components/announcements_page/announcements_page.js +++ b/src/components/announcements_page/announcements_page.js @@ -1,5 +1,6 @@ -import { useAnnouncementsStore } from 'src/stores/announcements' import { mapState } from 'vuex' + +import { useAnnouncementsStore } from 'src/stores/announcements' import Announcement from '../announcement/announcement.vue' import AnnouncementEditor from '../announcement_editor/announcement_editor.vue' diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js index 8c7700c8a..31fceba60 100644 --- a/src/components/attachment/attachment.js +++ b/src/components/attachment/attachment.js @@ -1,3 +1,12 @@ +import { mapGetters } from 'vuex' + +import { useMediaViewerStore } from 'src/stores/media_viewer' +import nsfwImage from '../../assets/nsfw.png' +import fileTypeService from '../../services/file_type/file_type.service.js' +import Flash from '../flash/flash.vue' +import StillImage from '../still-image/still-image.vue' +import VideoAttachment from '../video_attachment/video_attachment.vue' + import { library } from '@fortawesome/fontawesome-svg-core' import { faAlignRight, @@ -12,13 +21,6 @@ import { faTrashAlt, faVideo, } from '@fortawesome/free-solid-svg-icons' -import { useMediaViewerStore } from 'src/stores/media_viewer' -import { mapGetters } from 'vuex' -import nsfwImage from '../../assets/nsfw.png' -import fileTypeService from '../../services/file_type/file_type.service.js' -import Flash from '../flash/flash.vue' -import StillImage from '../still-image/still-image.vue' -import VideoAttachment from '../video_attachment/video_attachment.vue' library.add( faFile, diff --git a/src/components/auth_form/auth_form.js b/src/components/auth_form/auth_form.js index 1e9b86c57..ce88aa6f9 100644 --- a/src/components/auth_form/auth_form.js +++ b/src/components/auth_form/auth_form.js @@ -1,6 +1,7 @@ import { mapState } from 'pinia' -import { useAuthFlowStore } from 'src/stores/auth_flow' import { h, resolveComponent } from 'vue' + +import { useAuthFlowStore } from 'src/stores/auth_flow' import LoginForm from '../login_form/login_form.vue' import MFARecoveryForm from '../mfa_form/recovery_form.vue' import MFATOTPForm from '../mfa_form/totp_form.vue' diff --git a/src/components/block_card/block_card.js b/src/components/block_card/block_card.js index 754c2fb12..7301bf0c7 100644 --- a/src/components/block_card/block_card.js +++ b/src/components/block_card/block_card.js @@ -15,10 +15,10 @@ const BlockCard = { return this.relationship.blocking }, blockExpiryAvailable() { - return this.user.block_expires_at !== undefined + return Object.hasOwn(this.user, 'block_expires_at') }, blockExpiry() { - return this.user.block_expires_at == null + return this.user.block_expires_at === false ? this.$t('user_card.block_expires_forever') : this.$t('user_card.block_expires_at', [ new Date(this.user.mute_expires_at).toLocaleString(), diff --git a/src/components/bookmark_folders_menu/bookmark_folders_menu_content.js b/src/components/bookmark_folders_menu/bookmark_folders_menu_content.js index cc8135334..e84b3bc85 100644 --- a/src/components/bookmark_folders_menu/bookmark_folders_menu_content.js +++ b/src/components/bookmark_folders_menu/bookmark_folders_menu_content.js @@ -1,4 +1,5 @@ import { mapState } from 'pinia' + import { getBookmarkFolderEntries } from 'src/components/navigation/filter.js' import NavigationEntry from 'src/components/navigation/navigation_entry.vue' import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders' diff --git a/src/components/chat/chat.js b/src/components/chat/chat.js index 2a0d91761..6dd69ada4 100644 --- a/src/components/chat/chat.js +++ b/src/components/chat/chat.js @@ -1,9 +1,8 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faChevronDown, faChevronLeft } from '@fortawesome/free-solid-svg-icons' import _ from 'lodash' import { mapState as mapPiniaState } from 'pinia' -import { useInterfaceStore } from 'src/stores/interface.js' import { mapGetters, mapState } from 'vuex' + +import { useInterfaceStore } from 'src/stores/interface.js' import { WSConnectionStatus } from '../../services/api/api.service.js' import chatService from '../../services/chat_service/chat_service.js' import { buildFakeMessage } from '../../services/chat_utils/chat_utils.js' @@ -18,6 +17,9 @@ import { isScrollable, } from './chat_layout_utils.js' +import { library } from '@fortawesome/fontawesome-svg-core' +import { faChevronDown, faChevronLeft } from '@fortawesome/free-solid-svg-icons' + library.add(faChevronDown, faChevronLeft) const BOTTOMED_OUT_OFFSET = 10 diff --git a/src/components/chat_list/chat_list.js b/src/components/chat_list/chat_list.js index 8081d0670..4c3194ae1 100644 --- a/src/components/chat_list/chat_list.js +++ b/src/components/chat_list/chat_list.js @@ -1,4 +1,5 @@ import { mapGetters, mapState } from 'vuex' + import ChatListItem from '../chat_list_item/chat_list_item.vue' import ChatNew from '../chat_new/chat_new.vue' import List from '../list/list.vue' diff --git a/src/components/chat_list_item/chat_list_item.js b/src/components/chat_list_item/chat_list_item.js index ba8f5528b..0923a8568 100644 --- a/src/components/chat_list_item/chat_list_item.js +++ b/src/components/chat_list_item/chat_list_item.js @@ -1,5 +1,6 @@ -import fileType from 'src/services/file_type/file_type.service' import { mapState } from 'vuex' + +import fileType from 'src/services/file_type/file_type.service' import AvatarList from '../avatar_list/avatar_list.vue' import ChatTitle from '../chat_title/chat_title.vue' import StatusBody from '../status_content/status_content.vue' diff --git a/src/components/chat_message/chat_message.js b/src/components/chat_message/chat_message.js index 0d3876ab6..f3cc495c2 100644 --- a/src/components/chat_message/chat_message.js +++ b/src/components/chat_message/chat_message.js @@ -1,9 +1,8 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faEllipsisH, faTimes } from '@fortawesome/free-solid-svg-icons' import { mapState as mapPiniaState } from 'pinia' -import { useInterfaceStore } from 'src/stores/interface' import { defineAsyncComponent } from 'vue' import { mapGetters, mapState } from 'vuex' + +import { useInterfaceStore } from 'src/stores/interface' import Attachment from '../attachment/attachment.vue' import ChatMessageDate from '../chat_message_date/chat_message_date.vue' import Gallery from '../gallery/gallery.vue' @@ -12,6 +11,9 @@ import Popover from '../popover/popover.vue' import StatusContent from '../status_content/status_content.vue' import UserAvatar from '../user_avatar/user_avatar.vue' +import { library } from '@fortawesome/fontawesome-svg-core' +import { faEllipsisH, faTimes } from '@fortawesome/free-solid-svg-icons' + library.add(faTimes, faEllipsisH) const ChatMessage = { diff --git a/src/components/chat_new/chat_new.js b/src/components/chat_new/chat_new.js index d9f73193c..50e0f7a8f 100644 --- a/src/components/chat_new/chat_new.js +++ b/src/components/chat_new/chat_new.js @@ -1,9 +1,11 @@ -import { library } from '@fortawesome/fontawesome-svg-core' -import { faChevronLeft, faSearch } from '@fortawesome/free-solid-svg-icons' import { mapGetters, mapState } from 'vuex' + import BasicUserCard from '../basic_user_card/basic_user_card.vue' import UserAvatar from '../user_avatar/user_avatar.vue' +import { library } from '@fortawesome/fontawesome-svg-core' +import { faChevronLeft, faSearch } from '@fortawesome/free-solid-svg-icons' + library.add(faSearch, faChevronLeft) const chatNew = { diff --git a/src/components/chat_title/chat_title.js b/src/components/chat_title/chat_title.js index 7748f8973..3447f5163 100644 --- a/src/components/chat_title/chat_title.js +++ b/src/components/chat_title/chat_title.js @@ -1,5 +1,6 @@ -import RichContent from 'src/components/rich_content/rich_content.jsx' import { defineAsyncComponent } from 'vue' + +import RichContent from 'src/components/rich_content/rich_content.jsx' import UserAvatar from '../user_avatar/user_avatar.vue' export default { diff --git a/src/components/color_input/color_input.vue b/src/components/color_input/color_input.vue index 76a00416c..a6fc2047b 100644 --- a/src/components/color_input/color_input.vue +++ b/src/components/color_input/color_input.vue @@ -64,12 +64,14 @@