Merge branch 'release/rc-v1.2.0' of github.com:ONLYOFFICE/DocSpace into release/rc-v1.2.0

This commit is contained in:
Maksim Chegulov 2023-02-05 12:59:31 +03:00
commit 17a625252b
73 changed files with 4331 additions and 407 deletions

View File

@ -24,10 +24,9 @@ map $request_uri $header_x_frame_options {
map $request_uri $cache_control {
default "no-cache, no-store, no-transform";
~*\/(filehandler\.ashx\?action=thumb.*) "must-revalidate, no-transform, immutable, max-age=31536000";
~*\/(filehandler\.ashx\?action=thumb)|\/(storage\/room_logos\/root\/|storage\/userPhotos\/root\/) "must-revalidate, no-transform, immutable, max-age=31536000";
~*\/(api\/2\.0.*|storage|login\.ashx|filehandler\.ashx|ChunkedUploader.ashx|ThirdPartyAppHandler|apisystem|sh|remoteEntry\.js|debuginfo\.md|static\/scripts.*) "no-cache, no-store, no-transform";
~*\/(locales.*\.json) "must-revalidate, no-transform, max-age=900";
~*\/(images|favicon.ico.*)|\.(js|woff|woff2|css)|\/(storage\/room_logos\/root\/|storage\/userPhotos\/root\/) "must-revalidate, no-transform, immutable, max-age=31536000";
~*\/(images|favicon.ico.*)|\.(js|woff|woff2|css)|(locales.*\.json) "must-revalidate, no-transform, immutable, max-age=31536000";
}
include /etc/nginx/includes/onlyoffice-*.conf;
@ -114,6 +113,10 @@ server {
try_files /plugins/$basename /index.html =404;
}
location ~* /static/images/(.*)$ {
try_files /images/$1 /index.html =404;
}
}
location /doceditor {
@ -128,6 +131,14 @@ server {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
location ~* /static/images/(.*)$ {
try_files /images/$1 /index.html =404;
}
location ~* /static/fonts/ {
try_files /fonts/$basename /index.html =404;
}
}
location /login {
@ -142,6 +153,14 @@ server {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
location ~* /static/images/(.*)$ {
try_files /images/$1 /index.html =404;
}
location ~* /static/fonts/ {
try_files /fonts/$basename /index.html =404;
}
}
location /sockjs-node {

View File

@ -71,6 +71,7 @@
"html-webpack-plugin": "5.3.2",
"json-loader": "^0.5.7",
"playwright": "^1.18.1",
"prebuild-webpack-plugin": "^1.1.1",
"sass": "^1.39.2",
"sass-loader": "^12.1.0",
"serve": "14.1.1",

View File

@ -126,7 +126,7 @@
"PleaseNote": "Please note",
"PleaseNoteDescription": "<0>{{pleaseNote}}</0>: your old space address will become available to new users once you click the <2>{{save}}</2> button.",
"Plugins": "Plugins",
"PortalAccess": "Space access",
"PortalAccess": "Portal access",
"PortalAccessSubTitle": "This section allows you to provide users with safe and convenient ways to access the space.",
"PortalDeactivation": "Deactivate DocSpace",
"PortalDeactivationDescription": "Use this option to deactivate your space temporarily.",

View File

@ -3,7 +3,9 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -16,7 +16,6 @@ const DeleteDialogComponent = (props) => {
setBufferSelection,
setRemoveMediaItem,
setDeleteDialogVisible,
personal,
visible,
tReady,
isLoading,
@ -26,6 +25,8 @@ const DeleteDialogComponent = (props) => {
isRoomDelete,
setIsRoomDelete,
deleteRoomsAction,
isPersonalRoom,
isRoom,
} = props;
const selection = [];
@ -116,40 +117,34 @@ const DeleteDialogComponent = (props) => {
const moveToTrashNoteText = () => {
const isFolder = selection[0]?.isFolder || !!selection[0]?.parentId;
const { pathname } = location;
const isSingle = selection.length === 1;
if (selection.length > 1) {
if (isRoomDelete)
return `${t("DeleteRooms")} ${t("Common:WantToContinue")}`;
if (isRecycleBinFolder) {
return t("DeleteItems");
}
if (pathname.startsWith("/rooms/personal")) {
return t("MoveToTrashItemsFromPersonal");
} else if (pathname.startsWith("/rooms/shared")) {
return t("MoveToTrashItems");
}
} else {
if (isRoomDelete)
return `${t("DeleteRoom")} ${t("Common:WantToContinue")}`;
if (isRoomDelete) {
return isSingle
? `${t("DeleteRoom")} ${t("Common:WantToContinue")}`
: `${t("DeleteRooms")} ${t("Common:WantToContinue")}`;
}
if (pathname.startsWith("/rooms/personal")) {
return !isFolder
? t("MoveToTrashFileFromPersonal")
: personal
? ""
: t("MoveToTrashFolderFromPersonal");
} else if (pathname.startsWith("/rooms/shared")) {
return !isFolder
? t("MoveToTrashFile")
: personal
? ""
: t("MoveToTrashFolder");
}
if (isRecycleBinFolder) {
return isSingle
? t(isFolder ? "DeleteFolder" : "DeleteFile")
: t("DeleteItems");
}
if (isRecycleBinFolder) {
return t(isFolder ? "DeleteFolder" : "DeleteFile");
}
if (isPersonalRoom) {
return isSingle
? t(
isFolder
? "MoveToTrashFolderFromPersonal"
: "MoveToTrashFileFromPersonal"
)
: t("MoveToTrashItemsFromPersonal");
}
if (isRoom) {
return isSingle
? t(isFolder ? "MoveToTrashFolder" : "MoveToTrashFile")
: t("MoveToTrashItems");
}
};
@ -228,7 +223,12 @@ export default inject(
unsubscribeAction,
deleteRoomsAction,
} = filesActionsStore;
const { isPrivacyFolder, isRecycleBinFolder } = treeFoldersStore;
const {
isPrivacyFolder,
isRecycleBinFolder,
isPersonalRoom,
isRoom,
} = treeFoldersStore;
const {
deleteDialogVisible: visible,
@ -240,8 +240,6 @@ export default inject(
setIsRoomDelete,
} = dialogsStore;
const { personal } = auth.settingsStore;
return {
selection: removeMediaItem
? [removeMediaItem]
@ -259,13 +257,13 @@ export default inject(
unsubscribe,
setRemoveMediaItem,
personal,
setBufferSelection,
isRoomDelete,
setIsRoomDelete,
deleteRoomsAction,
isPersonalRoom,
isRoom,
};
}
)(withRouter(observer(DeleteDialog)));

View File

@ -3,7 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,9 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "./utils";
const newInstance = i18n.createInstance();

View File

@ -1,8 +1,9 @@
import authStore from "@docspace/common/store/AuthStore";
import { toCommunityHostname } from "@docspace/common/utils";
import { toCommunityHostname, getLanguage } from "@docspace/common/utils";
import history from "@docspace/common/history";
import { CategoryType } from "./constants";
import { FolderType } from "@docspace/common/constants";
import { translations } from "./autoGeneratedTranslations";
export const setDocumentTitle = (subTitle = null) => {
const { isAuthenticated, settingsStore, product: currentModule } = authStore;
@ -24,6 +25,31 @@ export const setDocumentTitle = (subTitle = null) => {
document.title = title;
};
export function loadLanguagePath(homepage, fixedNS = null) {
return (lng, ns) => {
const language = getLanguage(lng instanceof Array ? lng[0] : lng);
const lngCollection = translations.get(language);
const data = lngCollection?.get(`${fixedNS || ns}`);
if (!data) return `/locales/${language}/${fixedNS || ns}.json`;
let path = data?.split("/");
const length = path?.length;
const isCommonPath = path[length - 1].indexOf("Common") > -1;
path = `/${path[length - 3]}/${path[length - 2]}/${path[length - 1]}`;
if (ns.length > 0 && ns[0] === "Common" && isCommonPath) {
return `/static${path}`;
}
return path;
};
}
export const checkIfModuleOld = (link) => {
if (
!link ||

View File

@ -3,7 +3,9 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import config from "PACKAGE_FILE";
import { LANGUAGE } from "@docspace/common/constants";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "./helpers/utils";
const newInstance = i18n.createInstance();

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -3,7 +3,7 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -100,9 +100,9 @@ const Customization = (props) => {
{!isLoadedPage ? (
<LoaderDescriptionCustomization />
) : (
<div className="category-description">{`${t(
"Settings:CustomizationDescription"
)}`}</div>
<div className="category-description">
{t("Settings:CustomizationDescription")}
</div>
)}
<LanguageAndTimeZone isMobileView={isMobile} />
<StyledSettingsSeparator />

View File

@ -17,6 +17,7 @@ export const MainContainer = styled.div`
.subtitle {
margin-bottom: 20px;
color: ${(props) => props.theme.client.settings.common.descriptionColor};
}
.settings_tabs {

View File

@ -27,6 +27,10 @@ const MainContainer = styled.div`
max-width: 700px;
}
.login-history-description {
color: ${(props) => props.theme.client.settings.common.descriptionColor};
}
.save-cancel {
padding: 0;
position: static;
@ -184,7 +188,7 @@ const HistoryMainContent = (props) => {
<Badge backgroundColor="#EDC409" label="Paid" isPaidBadge={true} />
)}
<div className="main-wrapper">
<Text fontSize="13px" color="#657077" className="settings_unavailable">
<Text fontSize="13px" className="login-history-description">
{subHeader}
</Text>
<Text className="latest-text settings_unavailable">{latestText} </Text>

View File

@ -3,8 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "SRC_DIR/helpers/utils";
const newInstance = i18n.createInstance();
newInstance

View File

@ -682,6 +682,8 @@ class FilesStore {
console.log("[WS] subscribe to file's changes", file.id, file.title)
);
}
this.viewAs === "tile" && this.createThumbnails();
};
setFolders = (folders) => {
@ -1102,8 +1104,6 @@ class FilesStore {
selectedFolder: { ...this.selectedFolderStore },
};
this.viewAs === "tile" && this.createThumbnails();
if (this.createdItem) {
const newItem = this.filesList.find(
(item) => item.id === this.createdItem.id
@ -1237,8 +1237,6 @@ class FilesStore {
selectedFolder: { ...this.selectedFolderStore },
};
this.viewAs === "tile" && this.createThumbnails();
if (this.createdItem) {
const newItem = this.filesList.find(
(item) => item.id === this.createdItem.id
@ -2384,16 +2382,16 @@ class FilesStore {
isArchive
);
const defaultRoomIcon =
isRoom &&
getIcon(
iconSize,
fileExst,
providerKey,
contentLength,
roomType,
isArchive
);
const defaultRoomIcon = isRoom
? getIcon(
iconSize,
fileExst,
providerKey,
contentLength,
roomType,
isArchive
)
: undefined;
return {
access,
@ -2944,16 +2942,13 @@ class FilesStore {
};
createThumbnails = () => {
const filesList = [...this.files, this.folders];
const fileIds = [];
filesList.map((file) => {
const { thumbnailStatus } = file;
if (thumbnailStatus === thumbnailStatuses.WAITING) fileIds.push(file.id);
const files = this.files?.filter((file) => {
return file?.thumbnailStatus === thumbnailStatuses.WAITING;
});
if (fileIds.length) return api.files.createThumbnails(fileIds);
if (!files?.length) return;
return api.files.createThumbnails(files.map((f) => f.id));
};
createThumbnail = async (fileId) => {

View File

@ -199,6 +199,14 @@ class TreeFoldersStore {
);
}
get isRoom() {
return (
this.roomsFolder &&
this.roomsFolder.rootFolderType ===
this.selectedFolderStore.rootFolderType
);
}
get isArchiveFolder() {
return (
this.archiveFolder &&

View File

@ -4,13 +4,18 @@ const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack").container
.ModuleFederationPlugin;
const DefinePlugin = require("webpack").DefinePlugin;
const PrebuildWebpackPlugin = require("prebuild-webpack-plugin");
const ExternalTemplateRemotesPlugin = require("external-remotes-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const combineUrl = require("@docspace/common/utils/combineUrl");
const minifyJson = require("@docspace/common/utils/minifyJson");
const beforeBuild = require("@docspace/common/utils/beforeBuild");
const sharedDeps = require("@docspace/common/constants/sharedDependencies");
const fs = require("fs");
const { readdir } = require("fs").promises;
const path = require("path");
const pkg = require("./package.json");
const deps = pkg.dependencies || {};
const homepage = pkg.homepage; //combineUrl(window.DocSpaceConfig?.proxy?.url, pkg.homepage);
@ -98,7 +103,7 @@ const config = {
folder += result.length === 0 ? "" : "/";
return `${folder}[name][ext]?hash=[contenthash]`; // `${folder}/[name].[contenthash][ext]`;
return `static/${folder}[name][ext]?hash=[contenthash]`; // `${folder}/[name].[contenthash][ext]`;
},
},
@ -110,14 +115,50 @@ const config = {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|ico)$/i,
test: /\.(png|jpe?g|gif|ico|woff2)$/i,
type: "asset/resource",
generator: {
emit: false,
},
},
{
test: /\.svg$/i,
type: "asset/resource",
generator: {
emit: false,
},
resourceQuery: /url/, // *.svg?url
},
{
test: /\.json$/,
resourceQuery: /url/,
use: [
{
loader: "file-loader",
options: {
emitFile: false,
name: (resourcePath) => {
let result = resourcePath
.split(`public${path.sep}`)[1]
.split(path.sep);
result.pop();
let folder = result.join("/");
folder += result.length === 0 ? "" : "/";
return `${folder}[name].[ext]?hash=[contenthash]`; // `${folder}/[name].[contenthash][ext]`;
},
},
},
],
},
{
test: /\.json$/,
resourceQuery: { not: [/url/] }, // exclude if *.json?url,
loader: "json-loader",
},
{
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
@ -140,7 +181,6 @@ const config = {
fullySpecified: false,
},
},
{ test: /\.json$/, loader: "json-loader" },
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
@ -200,7 +240,17 @@ const config = {
plugins: [
new CleanWebpackPlugin(),
new ExternalTemplateRemotesPlugin(),
new PrebuildWebpackPlugin({
build: async (compiler, compilation, matchedFiles) => {
await beforeBuild(
[
path.join(__dirname, "./public/locales"),
path.join(__dirname, "../../public/locales"),
],
path.join(__dirname, "./src/helpers/autoGeneratedTranslations.js")
);
},
}),
new CopyPlugin({
patterns: [
// {

View File

@ -508,7 +508,7 @@ class MediaViewer extends React.Component {
const archiveRoom =
archiveRoomsId === targetFile.rootFolderId ||
(!targetFile.security.Rename && !targetFile.security.Delete);
(!targetFile?.security?.Rename && !targetFile?.security?.Delete);
const { title } = currentFile;
let isImage = false;

View File

@ -4,7 +4,7 @@
font-style: normal;
font-weight: 300;
src: local("Open Sans Light"), local("OpenSans-Light"),
url("/static/fonts/DXI1ORHCpsQm3Vp6mXoaTa-j2U0lmluP9RWlSytm3ho.woff2")
url("../../public/fonts/DXI1ORHCpsQm3Vp6mXoaTa-j2U0lmluP9RWlSytm3ho.woff2")
format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@ -14,7 +14,7 @@
font-style: normal;
font-weight: 300;
src: local("Open Sans Light"), local("OpenSans-Light"),
url("/static/fonts/DXI1ORHCpsQm3Vp6mXoaTZX5f-9o1vgP2EXwfjgl7AY.woff2")
url("../../public/fonts/DXI1ORHCpsQm3Vp6mXoaTZX5f-9o1vgP2EXwfjgl7AY.woff2")
format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@ -24,7 +24,7 @@
font-style: normal;
font-weight: 300;
src: local("Open Sans Light"), local("OpenSans-Light"),
url("/static/fonts/DXI1ORHCpsQm3Vp6mXoaTRWV49_lSm1NYrwo-zkhivY.woff2")
url("../../public/fonts/DXI1ORHCpsQm3Vp6mXoaTRWV49_lSm1NYrwo-zkhivY.woff2")
format("woff2");
unicode-range: U+1F00-1FFF;
}
@ -34,7 +34,7 @@
font-style: normal;
font-weight: 300;
src: local("Open Sans Light"), local("OpenSans-Light"),
url("/static/fonts/DXI1ORHCpsQm3Vp6mXoaTaaRobkAwv3vxw3jMhVENGA.woff2")
url("../../public/fonts/DXI1ORHCpsQm3Vp6mXoaTaaRobkAwv3vxw3jMhVENGA.woff2")
format("woff2");
unicode-range: U+0370-03FF;
}
@ -44,7 +44,7 @@
font-style: normal;
font-weight: 300;
src: local("Open Sans Light"), local("OpenSans-Light"),
url("/static/fonts/DXI1ORHCpsQm3Vp6mXoaTf8zf_FOSsgRmwsS7Aa9k2w.woff2")
url("../../public/fonts/DXI1ORHCpsQm3Vp6mXoaTf8zf_FOSsgRmwsS7Aa9k2w.woff2")
format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
@ -54,7 +54,7 @@
font-style: normal;
font-weight: 300;
src: local("Open Sans Light"), local("OpenSans-Light"),
url("/static/fonts/DXI1ORHCpsQm3Vp6mXoaTT0LW-43aMEzIO6XUTLjad8.woff2")
url("../../public/fonts/DXI1ORHCpsQm3Vp6mXoaTT0LW-43aMEzIO6XUTLjad8.woff2")
format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
@ -65,7 +65,7 @@
font-style: normal;
font-weight: 300;
src: local("Open Sans Light"), local("OpenSans-Light"),
url("/static/fonts/DXI1ORHCpsQm3Vp6mXoaTegdm0LZdjqr5-oayXSOefg.woff2")
url("../../public/fonts/DXI1ORHCpsQm3Vp6mXoaTegdm0LZdjqr5-oayXSOefg.woff2")
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
@ -76,7 +76,7 @@
font-style: normal;
font-weight: 400;
src: local("Open Sans"), local("OpenSans"),
url("/static/fonts/K88pR3goAWT7BTt32Z01mxJtnKITppOI_IvcXXDNrsc.woff2")
url("../../public/fonts/K88pR3goAWT7BTt32Z01mxJtnKITppOI_IvcXXDNrsc.woff2")
format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@ -86,7 +86,7 @@
font-style: normal;
font-weight: 400;
src: local("Open Sans"), local("OpenSans"),
url("/static/fonts/RjgO7rYTmqiVp7vzi-Q5URJtnKITppOI_IvcXXDNrsc.woff2")
url("../../public/fonts/RjgO7rYTmqiVp7vzi-Q5URJtnKITppOI_IvcXXDNrsc.woff2")
format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@ -96,7 +96,7 @@
font-style: normal;
font-weight: 400;
src: local("Open Sans"), local("OpenSans"),
url("/static/fonts/LWCjsQkB6EMdfHrEVqA1KRJtnKITppOI_IvcXXDNrsc.woff2")
url("../../public/fonts/LWCjsQkB6EMdfHrEVqA1KRJtnKITppOI_IvcXXDNrsc.woff2")
format("woff2");
unicode-range: U+1F00-1FFF;
}
@ -106,7 +106,7 @@
font-style: normal;
font-weight: 400;
src: local("Open Sans"), local("OpenSans"),
url("/static/fonts/xozscpT2726on7jbcb_pAhJtnKITppOI_IvcXXDNrsc.woff2")
url("../../public/fonts/xozscpT2726on7jbcb_pAhJtnKITppOI_IvcXXDNrsc.woff2")
format("woff2");
unicode-range: U+0370-03FF;
}
@ -116,7 +116,7 @@
font-style: normal;
font-weight: 400;
src: local("Open Sans"), local("OpenSans"),
url("/static/fonts/59ZRklaO5bWGqF5A9baEERJtnKITppOI_IvcXXDNrsc.woff2")
url("../../public/fonts/59ZRklaO5bWGqF5A9baEERJtnKITppOI_IvcXXDNrsc.woff2")
format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
@ -126,7 +126,7 @@
font-style: normal;
font-weight: 400;
src: local("Open Sans"), local("OpenSans"),
url("/static/fonts/u-WUoqrET9fUeobQW7jkRRJtnKITppOI_IvcXXDNrsc.woff2")
url("../../public/fonts/u-WUoqrET9fUeobQW7jkRRJtnKITppOI_IvcXXDNrsc.woff2")
format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
@ -137,7 +137,7 @@
font-style: normal;
font-weight: 400;
src: local("Open Sans"), local("OpenSans"),
url("/static/fonts/cJZKeOuBrn4kERxqtaUH3VtXRa8TVwTICgirnJhmVJw.woff2")
url("../../public/fonts/cJZKeOuBrn4kERxqtaUH3VtXRa8TVwTICgirnJhmVJw.woff2")
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
@ -148,7 +148,7 @@
font-style: normal;
font-weight: 600;
src: local("Open Sans Semibold"), local("OpenSans-Semibold"),
url("/static/fonts/MTP_ySUJH_bn48VBG8sNSq-j2U0lmluP9RWlSytm3ho.woff2")
url("../../public/fonts/MTP_ySUJH_bn48VBG8sNSq-j2U0lmluP9RWlSytm3ho.woff2")
format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@ -158,7 +158,7 @@
font-style: normal;
font-weight: 600;
src: local("Open Sans Semibold"), local("OpenSans-Semibold"),
url("/static/fonts/MTP_ySUJH_bn48VBG8sNSpX5f-9o1vgP2EXwfjgl7AY.woff2")
url("../../public/fonts/MTP_ySUJH_bn48VBG8sNSpX5f-9o1vgP2EXwfjgl7AY.woff2")
format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@ -168,7 +168,7 @@
font-style: normal;
font-weight: 600;
src: local("Open Sans Semibold"), local("OpenSans-Semibold"),
url("/static/fonts/MTP_ySUJH_bn48VBG8sNShWV49_lSm1NYrwo-zkhivY.woff2")
url("../../public/fonts/MTP_ySUJH_bn48VBG8sNShWV49_lSm1NYrwo-zkhivY.woff2")
format("woff2");
unicode-range: U+1F00-1FFF;
}
@ -178,7 +178,7 @@
font-style: normal;
font-weight: 600;
src: local("Open Sans Semibold"), local("OpenSans-Semibold"),
url("/static/fonts/MTP_ySUJH_bn48VBG8sNSqaRobkAwv3vxw3jMhVENGA.woff2")
url("../../public/fonts/MTP_ySUJH_bn48VBG8sNSqaRobkAwv3vxw3jMhVENGA.woff2")
format("woff2");
unicode-range: U+0370-03FF;
}
@ -188,7 +188,7 @@
font-style: normal;
font-weight: 600;
src: local("Open Sans Semibold"), local("OpenSans-Semibold"),
url("/static/fonts/MTP_ySUJH_bn48VBG8sNSv8zf_FOSsgRmwsS7Aa9k2w.woff2")
url("../../public/fonts/MTP_ySUJH_bn48VBG8sNSv8zf_FOSsgRmwsS7Aa9k2w.woff2")
format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
@ -198,7 +198,7 @@
font-style: normal;
font-weight: 600;
src: local("Open Sans Semibold"), local("OpenSans-Semibold"),
url("/static/fonts/MTP_ySUJH_bn48VBG8sNSj0LW-43aMEzIO6XUTLjad8.woff2")
url("../../public/fonts/MTP_ySUJH_bn48VBG8sNSj0LW-43aMEzIO6XUTLjad8.woff2")
format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
@ -209,7 +209,7 @@
font-style: normal;
font-weight: 600;
src: local("Open Sans Semibold"), local("OpenSans-Semibold"),
url("/static/fonts/MTP_ySUJH_bn48VBG8sNSugdm0LZdjqr5-oayXSOefg.woff2")
url("../../public/fonts/MTP_ySUJH_bn48VBG8sNSugdm0LZdjqr5-oayXSOefg.woff2")
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
@ -220,7 +220,7 @@
font-style: normal;
font-weight: 700;
src: local("Open Sans Bold"), local("OpenSans-Bold"),
url("/static/fonts/k3k702ZOKiLJc3WVjuplzK-j2U0lmluP9RWlSytm3ho.woff2")
url("../../public/fonts/k3k702ZOKiLJc3WVjuplzK-j2U0lmluP9RWlSytm3ho.woff2")
format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@ -230,7 +230,7 @@
font-style: normal;
font-weight: 700;
src: local("Open Sans Bold"), local("OpenSans-Bold"),
url("/static/fonts/k3k702ZOKiLJc3WVjuplzJX5f-9o1vgP2EXwfjgl7AY.woff2")
url("../../public/fonts/k3k702ZOKiLJc3WVjuplzJX5f-9o1vgP2EXwfjgl7AY.woff2")
format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@ -240,7 +240,7 @@
font-style: normal;
font-weight: 700;
src: local("Open Sans Bold"), local("OpenSans-Bold"),
url("/static/fonts/k3k702ZOKiLJc3WVjuplzBWV49_lSm1NYrwo-zkhivY.woff2")
url("../../public/fonts/k3k702ZOKiLJc3WVjuplzBWV49_lSm1NYrwo-zkhivY.woff2")
format("woff2");
unicode-range: U+1F00-1FFF;
}
@ -250,7 +250,7 @@
font-style: normal;
font-weight: 700;
src: local("Open Sans Bold"), local("OpenSans-Bold"),
url("/static/fonts/k3k702ZOKiLJc3WVjuplzKaRobkAwv3vxw3jMhVENGA.woff2")
url("../../public/fonts/k3k702ZOKiLJc3WVjuplzKaRobkAwv3vxw3jMhVENGA.woff2")
format("woff2");
unicode-range: U+0370-03FF;
}
@ -260,7 +260,7 @@
font-style: normal;
font-weight: 700;
src: local("Open Sans Bold"), local("OpenSans-Bold"),
url("/static/fonts/k3k702ZOKiLJc3WVjuplzP8zf_FOSsgRmwsS7Aa9k2w.woff2")
url("../../public/fonts/k3k702ZOKiLJc3WVjuplzP8zf_FOSsgRmwsS7Aa9k2w.woff2")
format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
@ -270,7 +270,7 @@
font-style: normal;
font-weight: 700;
src: local("Open Sans Bold"), local("OpenSans-Bold"),
url("/static/fonts/k3k702ZOKiLJc3WVjuplzD0LW-43aMEzIO6XUTLjad8.woff2")
url("../../public/fonts/k3k702ZOKiLJc3WVjuplzD0LW-43aMEzIO6XUTLjad8.woff2")
format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
@ -281,7 +281,7 @@
font-style: normal;
font-weight: 700;
src: local("Open Sans Bold"), local("OpenSans-Bold"),
url("/static/fonts/k3k702ZOKiLJc3WVjuplzOgdm0LZdjqr5-oayXSOefg.woff2")
url("../../public/fonts/k3k702ZOKiLJc3WVjuplzOgdm0LZdjqr5-oayXSOefg.woff2")
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
@ -292,7 +292,7 @@
font-style: normal;
font-weight: 800;
src: local("Open Sans Extrabold"), local("OpenSans-Extrabold"),
url("/static/fonts/EInbV5DfGHOiMmvb1Xr-hq-j2U0lmluP9RWlSytm3ho.woff2")
url("../../public/fonts/EInbV5DfGHOiMmvb1Xr-hq-j2U0lmluP9RWlSytm3ho.woff2")
format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@ -302,7 +302,7 @@
font-style: normal;
font-weight: 800;
src: local("Open Sans Extrabold"), local("OpenSans-Extrabold"),
url("/static/fonts/EInbV5DfGHOiMmvb1Xr-hpX5f-9o1vgP2EXwfjgl7AY.woff2")
url("../../public/fonts/EInbV5DfGHOiMmvb1Xr-hpX5f-9o1vgP2EXwfjgl7AY.woff2")
format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@ -312,7 +312,7 @@
font-style: normal;
font-weight: 800;
src: local("Open Sans Extrabold"), local("OpenSans-Extrabold"),
url("/static/fonts/EInbV5DfGHOiMmvb1Xr-hhWV49_lSm1NYrwo-zkhivY.woff2")
url("../../public/fonts/EInbV5DfGHOiMmvb1Xr-hhWV49_lSm1NYrwo-zkhivY.woff2")
format("woff2");
unicode-range: U+1F00-1FFF;
}
@ -322,7 +322,7 @@
font-style: normal;
font-weight: 800;
src: local("Open Sans Extrabold"), local("OpenSans-Extrabold"),
url("/static/fonts/EInbV5DfGHOiMmvb1Xr-hqaRobkAwv3vxw3jMhVENGA.woff2")
url("../../public/fonts/EInbV5DfGHOiMmvb1Xr-hqaRobkAwv3vxw3jMhVENGA.woff2")
format("woff2");
unicode-range: U+0370-03FF;
}
@ -332,7 +332,7 @@
font-style: normal;
font-weight: 800;
src: local("Open Sans Extrabold"), local("OpenSans-Extrabold"),
url("/static/fonts/EInbV5DfGHOiMmvb1Xr-hv8zf_FOSsgRmwsS7Aa9k2w.woff2")
url("../../public/fonts/EInbV5DfGHOiMmvb1Xr-hv8zf_FOSsgRmwsS7Aa9k2w.woff2")
format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
@ -342,7 +342,7 @@
font-style: normal;
font-weight: 800;
src: local("Open Sans Extrabold"), local("OpenSans-Extrabold"),
url("/static/fonts/EInbV5DfGHOiMmvb1Xr-hj0LW-43aMEzIO6XUTLjad8.woff2")
url("../../public/fonts/EInbV5DfGHOiMmvb1Xr-hj0LW-43aMEzIO6XUTLjad8.woff2")
format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
@ -353,7 +353,7 @@
font-style: normal;
font-weight: 800;
src: local("Open Sans Extrabold"), local("OpenSans-Extrabold"),
url("/static/fonts/EInbV5DfGHOiMmvb1Xr-hugdm0LZdjqr5-oayXSOefg.woff2")
url("../../public/fonts/EInbV5DfGHOiMmvb1Xr-hugdm0LZdjqr5-oayXSOefg.woff2")
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
@ -364,7 +364,7 @@
font-style: italic;
font-weight: 300;
src: local("Open Sans Light Italic"), local("OpenSansLight-Italic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxhgVThLs8Y7ETJzDCYFCSLE.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxhgVThLs8Y7ETJzDCYFCSLE.woff2")
format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@ -374,7 +374,7 @@
font-style: italic;
font-weight: 300;
src: local("Open Sans Light Italic"), local("OpenSansLight-Italic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxpiMaisvaUVUsYyVzOmndek.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxpiMaisvaUVUsYyVzOmndek.woff2")
format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@ -384,7 +384,7 @@
font-style: italic;
font-weight: 300;
src: local("Open Sans Light Italic"), local("OpenSansLight-Italic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxrBAWGjcah5Ky0jbCgIwDB8.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxrBAWGjcah5Ky0jbCgIwDB8.woff2")
format("woff2");
unicode-range: U+1F00-1FFF;
}
@ -394,7 +394,7 @@
font-style: italic;
font-weight: 300;
src: local("Open Sans Light Italic"), local("OpenSansLight-Italic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxv14vlcfyPYlAcQy2UfDRm4.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxv14vlcfyPYlAcQy2UfDRm4.woff2")
format("woff2");
unicode-range: U+0370-03FF;
}
@ -404,7 +404,7 @@
font-style: italic;
font-weight: 300;
src: local("Open Sans Light Italic"), local("OpenSansLight-Italic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxqfJul7RR1X4poJgi27uS4w.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxqfJul7RR1X4poJgi27uS4w.woff2")
format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
@ -414,7 +414,7 @@
font-style: italic;
font-weight: 300;
src: local("Open Sans Light Italic"), local("OpenSansLight-Italic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxqvyPXdneeGd26m9EmFSSWg.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxqvyPXdneeGd26m9EmFSSWg.woff2")
format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
@ -425,7 +425,7 @@
font-style: italic;
font-weight: 300;
src: local("Open Sans Light Italic"), local("OpenSansLight-Italic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxko2lTMeWA_kmIyWrkNCwPc.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxko2lTMeWA_kmIyWrkNCwPc.woff2")
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
@ -436,7 +436,7 @@
font-style: italic;
font-weight: 400;
src: local("Open Sans Italic"), local("OpenSans-Italic"),
url("/static/fonts/xjAJXh38I15wypJXxuGMBjTOQ_MqJVwkKsUn0wKzc2I.woff2")
url("../../public/fonts/xjAJXh38I15wypJXxuGMBjTOQ_MqJVwkKsUn0wKzc2I.woff2")
format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@ -446,7 +446,7 @@
font-style: italic;
font-weight: 400;
src: local("Open Sans Italic"), local("OpenSans-Italic"),
url("/static/fonts/xjAJXh38I15wypJXxuGMBjUj_cnvWIuuBMVgbX098Mw.woff2")
url("../../public/fonts/xjAJXh38I15wypJXxuGMBjUj_cnvWIuuBMVgbX098Mw.woff2")
format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@ -456,7 +456,7 @@
font-style: italic;
font-weight: 400;
src: local("Open Sans Italic"), local("OpenSans-Italic"),
url("/static/fonts/xjAJXh38I15wypJXxuGMBkbcKLIaa1LC45dFaAfauRA.woff2")
url("../../public/fonts/xjAJXh38I15wypJXxuGMBkbcKLIaa1LC45dFaAfauRA.woff2")
format("woff2");
unicode-range: U+1F00-1FFF;
}
@ -466,7 +466,7 @@
font-style: italic;
font-weight: 400;
src: local("Open Sans Italic"), local("OpenSans-Italic"),
url("/static/fonts/xjAJXh38I15wypJXxuGMBmo_sUJ8uO4YLWRInS22T3Y.woff2")
url("../../public/fonts/xjAJXh38I15wypJXxuGMBmo_sUJ8uO4YLWRInS22T3Y.woff2")
format("woff2");
unicode-range: U+0370-03FF;
}
@ -476,7 +476,7 @@
font-style: italic;
font-weight: 400;
src: local("Open Sans Italic"), local("OpenSans-Italic"),
url("/static/fonts/xjAJXh38I15wypJXxuGMBr6up8jxqWt8HVA3mDhkV_0.woff2")
url("../../public/fonts/xjAJXh38I15wypJXxuGMBr6up8jxqWt8HVA3mDhkV_0.woff2")
format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
@ -486,7 +486,7 @@
font-style: italic;
font-weight: 400;
src: local("Open Sans Italic"), local("OpenSans-Italic"),
url("/static/fonts/xjAJXh38I15wypJXxuGMBiYE0-AqJ3nfInTTiDXDjU4.woff2")
url("../../public/fonts/xjAJXh38I15wypJXxuGMBiYE0-AqJ3nfInTTiDXDjU4.woff2")
format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
@ -497,7 +497,7 @@
font-style: italic;
font-weight: 400;
src: local("Open Sans Italic"), local("OpenSans-Italic"),
url("/static/fonts/xjAJXh38I15wypJXxuGMBo4P5ICox8Kq3LLUNMylGO4.woff2")
url("../../public/fonts/xjAJXh38I15wypJXxuGMBo4P5ICox8Kq3LLUNMylGO4.woff2")
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
@ -508,7 +508,7 @@
font-style: italic;
font-weight: 600;
src: local("Open Sans Semibold Italic"), local("OpenSans-SemiboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxmgpAmOCqD37_tyH_8Ri5MM.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxmgpAmOCqD37_tyH_8Ri5MM.woff2")
format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@ -518,7 +518,7 @@
font-style: italic;
font-weight: 600;
src: local("Open Sans Semibold Italic"), local("OpenSans-SemiboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxsPNMTLbnS9uQzHQlYieHUU.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxsPNMTLbnS9uQzHQlYieHUU.woff2")
format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@ -528,7 +528,7 @@
font-style: italic;
font-weight: 600;
src: local("Open Sans Semibold Italic"), local("OpenSans-SemiboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxgyhumQnPMBCoGYhRaNxyyY.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxgyhumQnPMBCoGYhRaNxyyY.woff2")
format("woff2");
unicode-range: U+1F00-1FFF;
}
@ -538,7 +538,7 @@
font-style: italic;
font-weight: 600;
src: local("Open Sans Semibold Italic"), local("OpenSans-SemiboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxhUVAXEdVvYDDqrz3aeR0Yc.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxhUVAXEdVvYDDqrz3aeR0Yc.woff2")
format("woff2");
unicode-range: U+0370-03FF;
}
@ -548,7 +548,7 @@
font-style: italic;
font-weight: 600;
src: local("Open Sans Semibold Italic"), local("OpenSans-SemiboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxlf4y_3s5bcYyyLIFUSWYUU.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxlf4y_3s5bcYyyLIFUSWYUU.woff2")
format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
@ -558,7 +558,7 @@
font-style: italic;
font-weight: 600;
src: local("Open Sans Semibold Italic"), local("OpenSans-SemiboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxnywqdtBbUHn3VPgzuFrCy8.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxnywqdtBbUHn3VPgzuFrCy8.woff2")
format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
@ -569,7 +569,7 @@
font-style: italic;
font-weight: 600;
src: local("Open Sans Semibold Italic"), local("OpenSans-SemiboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxl2umOyRU7PgRiv8DXcgJjk.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxl2umOyRU7PgRiv8DXcgJjk.woff2")
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
@ -580,7 +580,7 @@
font-style: italic;
font-weight: 700;
src: local("Open Sans Bold Italic"), local("OpenSans-BoldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxp6iIh_FvlUHQwED9Yt5Kbw.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxp6iIh_FvlUHQwED9Yt5Kbw.woff2")
format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@ -590,7 +590,7 @@
font-style: italic;
font-weight: 700;
src: local("Open Sans Bold Italic"), local("OpenSans-BoldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxi_vZmeiCMnoWNN9rHBYaTc.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxi_vZmeiCMnoWNN9rHBYaTc.woff2")
format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@ -600,7 +600,7 @@
font-style: italic;
font-weight: 700;
src: local("Open Sans Bold Italic"), local("OpenSans-BoldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxiFaMxiho_5XQnyRZzQsrZs.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxiFaMxiho_5XQnyRZzQsrZs.woff2")
format("woff2");
unicode-range: U+1F00-1FFF;
}
@ -610,7 +610,7 @@
font-style: italic;
font-weight: 700;
src: local("Open Sans Bold Italic"), local("OpenSans-BoldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxgalQocB-__pDVGhF3uS2Ks.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxgalQocB-__pDVGhF3uS2Ks.woff2")
format("woff2");
unicode-range: U+0370-03FF;
}
@ -620,7 +620,7 @@
font-style: italic;
font-weight: 700;
src: local("Open Sans Bold Italic"), local("OpenSans-BoldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxmhQUTDJGru-0vvUpABgH8I.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxmhQUTDJGru-0vvUpABgH8I.woff2")
format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
@ -630,7 +630,7 @@
font-style: italic;
font-weight: 700;
src: local("Open Sans Bold Italic"), local("OpenSans-BoldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxujkDdvhIIFj_YMdgqpnSB0.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxujkDdvhIIFj_YMdgqpnSB0.woff2")
format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
@ -641,7 +641,7 @@
font-style: italic;
font-weight: 700;
src: local("Open Sans Bold Italic"), local("OpenSans-BoldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxolIZu-HDpmDIZMigmsroc4.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxolIZu-HDpmDIZMigmsroc4.woff2")
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
@ -652,7 +652,7 @@
font-style: italic;
font-weight: 800;
src: local("Open Sans Extrabold Italic"), local("OpenSans-ExtraboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxiU8QAtQT9M0M1_mbVWrUPc.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxiU8QAtQT9M0M1_mbVWrUPc.woff2")
format("woff2");
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
@ -662,7 +662,7 @@
font-style: italic;
font-weight: 800;
src: local("Open Sans Extrabold Italic"), local("OpenSans-ExtraboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxkNaUOL0oYRolx8sebiIY9k.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxkNaUOL0oYRolx8sebiIY9k.woff2")
format("woff2");
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@ -672,7 +672,7 @@
font-style: italic;
font-weight: 800;
src: local("Open Sans Extrabold Italic"), local("OpenSans-ExtraboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxooGEx1DzoxsbCRd2IM2afI.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxooGEx1DzoxsbCRd2IM2afI.woff2")
format("woff2");
unicode-range: U+1F00-1FFF;
}
@ -682,7 +682,7 @@
font-style: italic;
font-weight: 800;
src: local("Open Sans Extrabold Italic"), local("OpenSans-ExtraboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxnPzCMEhbIaaYiFY6KPniws.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxnPzCMEhbIaaYiFY6KPniws.woff2")
format("woff2");
unicode-range: U+0370-03FF;
}
@ -692,7 +692,7 @@
font-style: italic;
font-weight: 800;
src: local("Open Sans Extrabold Italic"), local("OpenSans-ExtraboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxmqi69zMYkLa7XwlUIemKB4.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxmqi69zMYkLa7XwlUIemKB4.woff2")
format("woff2");
unicode-range: U+0102-0103, U+1EA0-1EF1, U+20AB;
}
@ -702,7 +702,7 @@
font-style: italic;
font-weight: 800;
src: local("Open Sans Extrabold Italic"), local("OpenSans-ExtraboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxowYyzpnB4tyYboSwKGmD2g.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxowYyzpnB4tyYboSwKGmD2g.woff2")
format("woff2");
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F,
U+A720-A7FF;
@ -713,7 +713,7 @@
font-style: italic;
font-weight: 800;
src: local("Open Sans Extrabold Italic"), local("OpenSans-ExtraboldItalic"),
url("/static/fonts/PRmiXeptR36kaC0GEAetxnibbpXgLHK_uTT48UMyjSM.woff2")
url("../../public/fonts/PRmiXeptR36kaC0GEAetxnibbpXgLHK_uTT48UMyjSM.woff2")
format("woff2");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC,
U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;

View File

@ -7,7 +7,7 @@ import i18n from "i18next";
import { useTranslation, initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "../constants";
import { loadLanguagePath, getCookie } from "../utils";
import { getCookie } from "../utils";
i18n
.use(Backend)

View File

@ -0,0 +1,125 @@
const path = require("path");
const fs = require("fs");
const { readdir } = require("fs").promises;
const appSettings = require("../../../config/appsettings.json");
const beforeBuild = async (pathsToLocales, pathToFile) => {
async function* getFiles(dir) {
const dirents = await readdir(dir, { withFileTypes: true });
for (const dirent of dirents) {
const res = path.resolve(dir, dirent.name);
if (dirent.isDirectory()) {
yield* getFiles(res);
} else {
yield { path: res, fileName: dirent.name };
}
}
}
const getLocalesFiles = async () => {
const files = [];
for await (const p of pathsToLocales) {
for await (const f of getFiles(p)) {
if (f) files.push(f);
}
}
return files;
};
const localesFiles = await getLocalesFiles();
const cultures = appSettings.web.cultures;
const collectionByLng = new Map();
const truthLng = new Map();
let importString = "\n";
localesFiles.forEach((file) => {
const splitPath = file.path.split(path.sep);
const length = splitPath.length;
const url = [
splitPath[length - 3],
splitPath[length - 2],
splitPath[length - 1],
].join("/");
const fileName = splitPath[length - 1].split(".")[0];
let lng = splitPath[length - 2];
let language = lng == "en-US" || lng == "en-GB" ? "en" : lng;
if (cultures.indexOf(language) === -1) {
return;
}
const splitted = lng.split("-");
if (splitted.length == 2 && splitted[0] == splitted[1].toLowerCase()) {
language = splitted[0];
}
truthLng.set(language, language.replace("-", ""));
language = language.replace("-", "");
const items = collectionByLng.get(language);
if (items && items.length > 0) {
items.push(fileName);
collectionByLng.set(language, items);
} else {
collectionByLng.set(language, [fileName]);
}
const alias =
fileName.indexOf("Common") === -1 ? "ASSETS_DIR" : "PUBLIC_DIR";
importString =
importString +
`import ${fileName}${language}Url from "${alias}/${url}?url";\n`;
});
let content =
`//THIS FILE IS AUTO GENERATED\n//DO NOT EDIT AND DELETE IT\n` +
importString;
let generalCollection = `\n export const translations = new Map([`;
collectionByLng.forEach((collection, key) => {
let collectionString = `\n const ${key} = new Map([`;
collection.forEach((c, index) => {
collectionString += `\n["${c}", ${c}${key}Url]`;
if (index !== collection.length - 1) collectionString += `,`;
});
collectionString += `\n]);`;
content += collectionString;
});
truthLng.forEach((col, key) => {
generalCollection += `\n["${key}", ${col}],`;
});
generalCollection += `\n]);`;
content += generalCollection;
fs.writeFile(pathToFile, content, "utf8", function (err) {
if (err) throw new Error(Error);
console.log("The auto generated translations file has been created!");
});
};
module.exports = beforeBuild;

View File

@ -22,6 +22,7 @@ import TopLoaderService from "@docspace/components/top-loading-indicator";
import { Encoder } from "./encoder";
import FilesFilter from "../api/files/filter";
import combineUrlFunc from "./combineUrl";
// import { translations } from "./i18next-http-backend/lib/translations";
export const toUrlParams = (obj, skipNull) => {
let str = "";
for (var key in obj) {
@ -291,17 +292,6 @@ export function getLanguage(lng) {
return lng;
}
export function loadLanguagePath(homepage, fixedNS = null) {
return (lng, ns) => {
const language = getLanguage(lng instanceof Array ? lng[0] : lng);
if (ns.length > 0 && ns[0] === "Common") {
return `/static/locales/${language}/Common.json`;
}
return `${homepage}/locales/${language}/${fixedNS || ns}.json`;
};
}
export function loadScript(url, id, onLoad, onError) {
try {
const script = document.createElement("script");

View File

@ -43,6 +43,7 @@
"json-loader": "^0.5.7",
"nodemon": "^2.0.7",
"npm-run-all": "^4.1.5",
"prebuild-webpack-plugin": "^1.1.1",
"sass": "^1.53.0",
"sass-loader": "^13.0.2",
"shx": "^0.3.4",

View File

@ -0,0 +1,188 @@
//THIS FILE IS AUTO GENERATED
//DO NOT EDIT AND DELETE IT
import EditorazUrl from "ASSETS_DIR/locales/az/Editor.json?url";
import EditorbgUrl from "ASSETS_DIR/locales/bg/Editor.json?url";
import EditorcsUrl from "ASSETS_DIR/locales/cs/Editor.json?url";
import EditordeUrl from "ASSETS_DIR/locales/de/Editor.json?url";
import EditorelGRUrl from "ASSETS_DIR/locales/el-GR/Editor.json?url";
import EditorenUrl from "ASSETS_DIR/locales/en/Editor.json?url";
import EditoresUrl from "ASSETS_DIR/locales/es/Editor.json?url";
import EditorfiUrl from "ASSETS_DIR/locales/fi/Editor.json?url";
import EditorfrUrl from "ASSETS_DIR/locales/fr/Editor.json?url";
import EditoritUrl from "ASSETS_DIR/locales/it/Editor.json?url";
import EditorjaJPUrl from "ASSETS_DIR/locales/ja-JP/Editor.json?url";
import EditorkoKRUrl from "ASSETS_DIR/locales/ko-KR/Editor.json?url";
import EditorloLAUrl from "ASSETS_DIR/locales/lo-LA/Editor.json?url";
import EditorlvUrl from "ASSETS_DIR/locales/lv/Editor.json?url";
import EditornlUrl from "ASSETS_DIR/locales/nl/Editor.json?url";
import EditorplUrl from "ASSETS_DIR/locales/pl/Editor.json?url";
import EditorptUrl from "ASSETS_DIR/locales/pt/Editor.json?url";
import EditorptBRUrl from "ASSETS_DIR/locales/pt-BR/Editor.json?url";
import EditorroUrl from "ASSETS_DIR/locales/ro/Editor.json?url";
import EditorruUrl from "ASSETS_DIR/locales/ru/Editor.json?url";
import EditorskUrl from "ASSETS_DIR/locales/sk/Editor.json?url";
import EditorslUrl from "ASSETS_DIR/locales/sl/Editor.json?url";
import EditortrUrl from "ASSETS_DIR/locales/tr/Editor.json?url";
import EditorukUAUrl from "ASSETS_DIR/locales/uk-UA/Editor.json?url";
import EditorviUrl from "ASSETS_DIR/locales/vi/Editor.json?url";
import EditorzhCNUrl from "ASSETS_DIR/locales/zh-CN/Editor.json?url";
import CommonazUrl from "PUBLIC_DIR/locales/az/Common.json?url";
import CommonbgUrl from "PUBLIC_DIR/locales/bg/Common.json?url";
import CommoncsUrl from "PUBLIC_DIR/locales/cs/Common.json?url";
import CommondeUrl from "PUBLIC_DIR/locales/de/Common.json?url";
import CommonelGRUrl from "PUBLIC_DIR/locales/el-GR/Common.json?url";
import CommonenUrl from "PUBLIC_DIR/locales/en/Common.json?url";
import CommonesUrl from "PUBLIC_DIR/locales/es/Common.json?url";
import CommonfiUrl from "PUBLIC_DIR/locales/fi/Common.json?url";
import CommonfrUrl from "PUBLIC_DIR/locales/fr/Common.json?url";
import CommonitUrl from "PUBLIC_DIR/locales/it/Common.json?url";
import CommonjaJPUrl from "PUBLIC_DIR/locales/ja-JP/Common.json?url";
import CommonkoKRUrl from "PUBLIC_DIR/locales/ko-KR/Common.json?url";
import CommonloLAUrl from "PUBLIC_DIR/locales/lo-LA/Common.json?url";
import CommonlvUrl from "PUBLIC_DIR/locales/lv/Common.json?url";
import CommonnlUrl from "PUBLIC_DIR/locales/nl/Common.json?url";
import CommonplUrl from "PUBLIC_DIR/locales/pl/Common.json?url";
import CommonptUrl from "PUBLIC_DIR/locales/pt/Common.json?url";
import CommonptBRUrl from "PUBLIC_DIR/locales/pt-BR/Common.json?url";
import CommonroUrl from "PUBLIC_DIR/locales/ro/Common.json?url";
import CommonruUrl from "PUBLIC_DIR/locales/ru/Common.json?url";
import CommonskUrl from "PUBLIC_DIR/locales/sk/Common.json?url";
import CommonslUrl from "PUBLIC_DIR/locales/sl/Common.json?url";
import CommontrUrl from "PUBLIC_DIR/locales/tr/Common.json?url";
import CommonukUAUrl from "PUBLIC_DIR/locales/uk-UA/Common.json?url";
import CommonviUrl from "PUBLIC_DIR/locales/vi/Common.json?url";
import CommonzhCNUrl from "PUBLIC_DIR/locales/zh-CN/Common.json?url";
const az = new Map([
["Editor", EditorazUrl],
["Common", CommonazUrl]
]);
const bg = new Map([
["Editor", EditorbgUrl],
["Common", CommonbgUrl]
]);
const cs = new Map([
["Editor", EditorcsUrl],
["Common", CommoncsUrl]
]);
const de = new Map([
["Editor", EditordeUrl],
["Common", CommondeUrl]
]);
const elGR = new Map([
["Editor", EditorelGRUrl],
["Common", CommonelGRUrl]
]);
const en = new Map([
["Editor", EditorenUrl],
["Common", CommonenUrl]
]);
const es = new Map([
["Editor", EditoresUrl],
["Common", CommonesUrl]
]);
const fi = new Map([
["Editor", EditorfiUrl],
["Common", CommonfiUrl]
]);
const fr = new Map([
["Editor", EditorfrUrl],
["Common", CommonfrUrl]
]);
const it = new Map([
["Editor", EditoritUrl],
["Common", CommonitUrl]
]);
const jaJP = new Map([
["Editor", EditorjaJPUrl],
["Common", CommonjaJPUrl]
]);
const koKR = new Map([
["Editor", EditorkoKRUrl],
["Common", CommonkoKRUrl]
]);
const loLA = new Map([
["Editor", EditorloLAUrl],
["Common", CommonloLAUrl]
]);
const lv = new Map([
["Editor", EditorlvUrl],
["Common", CommonlvUrl]
]);
const nl = new Map([
["Editor", EditornlUrl],
["Common", CommonnlUrl]
]);
const pl = new Map([
["Editor", EditorplUrl],
["Common", CommonplUrl]
]);
const pt = new Map([
["Editor", EditorptUrl],
["Common", CommonptUrl]
]);
const ptBR = new Map([
["Editor", EditorptBRUrl],
["Common", CommonptBRUrl]
]);
const ro = new Map([
["Editor", EditorroUrl],
["Common", CommonroUrl]
]);
const ru = new Map([
["Editor", EditorruUrl],
["Common", CommonruUrl]
]);
const sk = new Map([
["Editor", EditorskUrl],
["Common", CommonskUrl]
]);
const sl = new Map([
["Editor", EditorslUrl],
["Common", CommonslUrl]
]);
const tr = new Map([
["Editor", EditortrUrl],
["Common", CommontrUrl]
]);
const ukUA = new Map([
["Editor", EditorukUAUrl],
["Common", CommonukUAUrl]
]);
const vi = new Map([
["Editor", EditorviUrl],
["Common", CommonviUrl]
]);
const zhCN = new Map([
["Editor", EditorzhCNUrl],
["Common", CommonzhCNUrl]
]);
export const translations = new Map([
["az", az],
["bg", bg],
["cs", cs],
["de", de],
["el-GR", elGR],
["en", en],
["es", es],
["fi", fi],
["fr", fr],
["it", it],
["ja-JP", jaJP],
["ko-KR", koKR],
["lo-LA", loLA],
["lv", lv],
["nl", nl],
["pl", pl],
["pt", pt],
["pt-BR", ptBR],
["ro", ro],
["ru", ru],
["sk", sk],
["sl", sl],
["tr", tr],
["uk-UA", ukUA],
["vi", vi],
["zh-CN", zhCN],
]);

View File

@ -1,6 +1,6 @@
import React from "react";
import { hydrate } from "react-dom";
import { registerSW } from "@docspace/common/sw/helper";
// import { registerSW } from "@docspace/common/sw/helper";
import App from "./App.js";
import pkg from "../../package.json";
import { initI18n } from "./helpers/utils.js";
@ -53,4 +53,4 @@ if (IS_DEVELOPMENT) {
};
}
registerSW();
// registerSW();

View File

@ -1,26 +1,74 @@
import pkg from "../../../package.json";
import { translations } from "SRC_DIR/autoGeneratedTranslations";
export function getLanguage(lng) {
try {
let language = lng == "en-US" || lng == "en-GB" ? "en" : lng;
const splitted = lng.split("-");
if (splitted.length == 2 && splitted[0] == splitted[1].toLowerCase()) {
language = splitted[0];
}
return language;
} catch (error) {
console.error(error);
}
return lng;
}
export function loadLanguagePath(homepage, fixedNS = null) {
return (lng, ns) => {
const language = getLanguage(lng instanceof Array ? lng[0] : lng);
const lngCollection = translations.get(language);
const path = lngCollection?.get(`${fixedNS || ns}`);
if (!path) return `/doceditor/locales/${language}/${fixedNS || ns}.json`;
const isCommonPath = path?.indexOf("Common") > -1;
if (ns.length > 0 && ns[0] === "Common" && isCommonPath) {
return path.replace("/doceditor/", "/static/");
}
return path;
};
}
export const initI18n = (initialI18nStoreASC) => {
if (!initialI18nStoreASC || window.i18n) return;
const { homepage } = pkg;
window.i18n = {};
window.i18n.inLoad = [];
window.i18n.loaded = {};
for (let lng in initialI18nStoreASC) {
const collection = translations.get(lng);
for (let ns in initialI18nStoreASC[lng]) {
if (ns === "Common") {
window.i18n.loaded[`/static/locales/${lng}/${ns}.json`] = {
const path = collection?.get(ns);
if (!path) {
window.i18n.loaded[`/doceditor/locales/${lng}/${ns}.json`] = {
namespaces: ns,
data: initialI18nStoreASC[lng][ns],
};
} else {
window.i18n.loaded[`${homepage}/locales/${lng}/${ns}.json`] = {
namespaces: ns,
data: initialI18nStoreASC[lng][ns],
};
if (ns === "Common") {
window.i18n.loaded[`${path?.replace("/doceditor/", "/static/")}`] = {
namespaces: ns,
data: initialI18nStoreASC[lng][ns],
};
} else {
window.i18n.loaded[`${path}`] = {
namespaces: ns,
data: initialI18nStoreASC[lng][ns],
};
}
}
}
}

View File

@ -3,7 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import config from "../../package.json";
import { LANGUAGE } from "@docspace/common/constants";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "./helpers/utils";
const newInstance = i18n.createInstance();

View File

@ -13,6 +13,7 @@ import winston from "./lib/logger.js";
import { getAssets, initDocEditor } from "./lib/helpers";
import renderApp from "./lib/helpers/render-app";
import dns from "dns";
import { translations } from "SRC_DIR/autoGeneratedTranslations";
dns.setDefaultResultOrder("ipv4first");
@ -32,15 +33,9 @@ winston.stream = {
};
const loadPath = (lng, ns) => {
let resourcePath = path.resolve(
path.join(__dirname, "client", `locales/${lng}/${ns}.json`)
);
if (ns === "Common")
resourcePath = path.resolve(
path.join(__dirname, `../../../public/locales/${lng}/${ns}.json`)
);
const path = translations?.get(lng)?.get(ns);
return resourcePath;
return path;
};
const app = express();

View File

@ -20,10 +20,7 @@ import { getLogoFromPath } from "@docspace/common/utils";
export const getFavicon = (logoUrls) => {
if (!logoUrls) return null;
return getLogoFromPath(logoUrls[2]?.path?.light).replace(
"client/",
"/doceditor/"
);
return getLogoFromPath(logoUrls[2]?.path?.light);
};
export const initDocEditor = async (req) => {
@ -114,23 +111,16 @@ export const initDocEditor = async (req) => {
config.editorConfig.customization.logo.image =
config.editorConfig.customization.logo.url +
getLogoFromPath(config.editorConfig.customization.logo.image)?.replace(
"client/",
"doceditor/"
);
getLogoFromPath(config.editorConfig.customization.logo.image);
config.editorConfig.customization.logo.imageDark =
config.editorConfig.customization.logo.url +
getLogoFromPath(
config.editorConfig.customization.logo.imageDark
)?.replace("client/", "doceditor/");
getLogoFromPath(config.editorConfig.customization.logo.imageDark);
if (config.editorConfig.customization.customer) {
config.editorConfig.customization.customer.logo =
config.editorConfig.customization.logo.url +
getLogoFromPath(
config.editorConfig.customization.customer.logo
)?.replace("client/", "doceditor/");
getLogoFromPath(config.editorConfig.customization.customer.logo);
}
return {

View File

@ -12,10 +12,7 @@ export default function template(
const { title } = pkg;
const { error } = initialEditorState;
const editorUrl = initialEditorState?.config?.editorUrl;
const faviconHref = getFavicon(initialEditorState?.logoUrls)?.replace(
"client/",
"doceditor/"
);
const faviconHref = getFavicon(initialEditorState?.logoUrls);
let clientScripts =
assets && assets.hasOwnProperty("client.js")

View File

@ -1,5 +1,7 @@
const path = require("path");
const FilterWarningsPlugin = require("webpack-filter-warnings-plugin");
const PrebuildWebpackPlugin = require("prebuild-webpack-plugin");
const beforeBuild = require("@docspace/common/utils/beforeBuild");
const scriptExtensions = /\.(tsx|ts|js|jsx|mjs)$/;
const imageExtensions = /\.(bmp|gif|jpg|jpeg|png|ico)$/;
@ -13,6 +15,7 @@ module.exports = {
},
alias: {
PUBLIC_DIR: path.resolve(__dirname, "../../../public"),
ASSETS_DIR: path.resolve(__dirname, "../public"),
SRC_DIR: path.resolve(__dirname, "../src"),
PACKAGE_FILE: path.resolve(__dirname, "../package.json"),
},
@ -42,7 +45,10 @@ module.exports = {
},
{
test: fontsExtension,
type: "asset",
generator: {
emit: false,
},
type: "asset/resource",
},
{
test: /\.svg/,
@ -52,13 +58,51 @@ module.exports = {
},
{
test: imageExtensions,
generator: {
emit: false,
},
type: "asset/resource",
},
{
test: /\.svg$/i,
generator: {
emit: false,
},
type: "asset/resource",
resourceQuery: /url/, // *.svg?url
},
{
test: /\.json$/,
resourceQuery: /url/,
type: "javascript/auto",
use: [
{
loader: "file-loader",
options: {
emitFile: false,
name: (resourcePath) => {
let result = resourcePath
.split(`public${path.sep}`)[1]
.split(path.sep);
result.pop();
let folder = result.join("/");
folder += result.length === 0 ? "" : "/";
return `${folder}[name].[ext]?hash=[contenthash]`; // `${folder}/[name].[contenthash][ext]`;
},
},
},
],
},
{
test: /\.json$/,
resourceQuery: { not: [/url/] }, // exclude if *.json?url,
loader: "json-loader",
type: "javascript/auto",
},
],
},
plugins: [

View File

@ -9,6 +9,8 @@ const ExternalTemplateRemotesPlugin = require("external-remotes-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const minifyJson = require("@docspace/common/utils/minifyJson");
const PrebuildWebpackPlugin = require("prebuild-webpack-plugin");
const beforeBuild = require("@docspace/common/utils/beforeBuild");
const sharedDeps = require("@docspace/common/constants/sharedDependencies");
const baseConfig = require("./webpack.base.js");
@ -44,7 +46,7 @@ const clientConfig = {
folder += result.length === 0 ? "" : "/";
return `${folder}[name][ext]?hash=[contenthash]`; //`${folder}/[name].[contenthash][ext]`;
return `static/${folder}[name][ext]?hash=[contenthash]`; //`${folder}/[name].[contenthash][ext]`;
},
},
@ -109,6 +111,17 @@ const clientConfig = {
],
}),
new WebpackManifestPlugin(),
new PrebuildWebpackPlugin({
build: async (compiler, compilation, matchedFiles) => {
await beforeBuild(
[
path.join(__dirname, "../public/locales"),
path.join(__dirname, "../../../public/locales"),
],
path.join(__dirname, "../src/autoGeneratedTranslations.js")
);
},
}),
],
};

View File

@ -31,7 +31,7 @@ const serverConfig = {
folder += result.length === 0 ? "" : "/";
return `client/${folder}[name][ext]?hash=[contenthash]`; //`${folder}/[name].[contenthash][ext]`;
return `/doceditor/static/${folder}[name][ext]?hash=[contenthash]`; //`${folder}/[name].[contenthash][ext]`;
},
},

View File

@ -87,6 +87,7 @@
"nodemon": "^2.0.19",
"npm-run-all": "^4.1.5",
"playwright": "^1.17.1",
"prebuild-webpack-plugin": "^1.1.1",
"sass": "^1.39.2",
"sass-loader": "^12.1.0",
"serve": "14.1.1",

View File

@ -0,0 +1,188 @@
//THIS FILE IS AUTO GENERATED
//DO NOT EDIT AND DELETE IT
import LoginazUrl from "ASSETS_DIR/locales/az/Login.json?url";
import LoginbgUrl from "ASSETS_DIR/locales/bg/Login.json?url";
import LogincsUrl from "ASSETS_DIR/locales/cs/Login.json?url";
import LogindeUrl from "ASSETS_DIR/locales/de/Login.json?url";
import LoginelGRUrl from "ASSETS_DIR/locales/el-GR/Login.json?url";
import LoginenUrl from "ASSETS_DIR/locales/en/Login.json?url";
import LoginesUrl from "ASSETS_DIR/locales/es/Login.json?url";
import LoginfiUrl from "ASSETS_DIR/locales/fi/Login.json?url";
import LoginfrUrl from "ASSETS_DIR/locales/fr/Login.json?url";
import LoginitUrl from "ASSETS_DIR/locales/it/Login.json?url";
import LoginjaJPUrl from "ASSETS_DIR/locales/ja-JP/Login.json?url";
import LoginkoKRUrl from "ASSETS_DIR/locales/ko-KR/Login.json?url";
import LoginloLAUrl from "ASSETS_DIR/locales/lo-LA/Login.json?url";
import LoginlvUrl from "ASSETS_DIR/locales/lv/Login.json?url";
import LoginnlUrl from "ASSETS_DIR/locales/nl/Login.json?url";
import LoginplUrl from "ASSETS_DIR/locales/pl/Login.json?url";
import LoginptUrl from "ASSETS_DIR/locales/pt/Login.json?url";
import LoginptBRUrl from "ASSETS_DIR/locales/pt-BR/Login.json?url";
import LoginroUrl from "ASSETS_DIR/locales/ro/Login.json?url";
import LoginruUrl from "ASSETS_DIR/locales/ru/Login.json?url";
import LoginskUrl from "ASSETS_DIR/locales/sk/Login.json?url";
import LoginslUrl from "ASSETS_DIR/locales/sl/Login.json?url";
import LogintrUrl from "ASSETS_DIR/locales/tr/Login.json?url";
import LoginukUAUrl from "ASSETS_DIR/locales/uk-UA/Login.json?url";
import LoginviUrl from "ASSETS_DIR/locales/vi/Login.json?url";
import LoginzhCNUrl from "ASSETS_DIR/locales/zh-CN/Login.json?url";
import CommonazUrl from "PUBLIC_DIR/locales/az/Common.json?url";
import CommonbgUrl from "PUBLIC_DIR/locales/bg/Common.json?url";
import CommoncsUrl from "PUBLIC_DIR/locales/cs/Common.json?url";
import CommondeUrl from "PUBLIC_DIR/locales/de/Common.json?url";
import CommonelGRUrl from "PUBLIC_DIR/locales/el-GR/Common.json?url";
import CommonenUrl from "PUBLIC_DIR/locales/en/Common.json?url";
import CommonesUrl from "PUBLIC_DIR/locales/es/Common.json?url";
import CommonfiUrl from "PUBLIC_DIR/locales/fi/Common.json?url";
import CommonfrUrl from "PUBLIC_DIR/locales/fr/Common.json?url";
import CommonitUrl from "PUBLIC_DIR/locales/it/Common.json?url";
import CommonjaJPUrl from "PUBLIC_DIR/locales/ja-JP/Common.json?url";
import CommonkoKRUrl from "PUBLIC_DIR/locales/ko-KR/Common.json?url";
import CommonloLAUrl from "PUBLIC_DIR/locales/lo-LA/Common.json?url";
import CommonlvUrl from "PUBLIC_DIR/locales/lv/Common.json?url";
import CommonnlUrl from "PUBLIC_DIR/locales/nl/Common.json?url";
import CommonplUrl from "PUBLIC_DIR/locales/pl/Common.json?url";
import CommonptUrl from "PUBLIC_DIR/locales/pt/Common.json?url";
import CommonptBRUrl from "PUBLIC_DIR/locales/pt-BR/Common.json?url";
import CommonroUrl from "PUBLIC_DIR/locales/ro/Common.json?url";
import CommonruUrl from "PUBLIC_DIR/locales/ru/Common.json?url";
import CommonskUrl from "PUBLIC_DIR/locales/sk/Common.json?url";
import CommonslUrl from "PUBLIC_DIR/locales/sl/Common.json?url";
import CommontrUrl from "PUBLIC_DIR/locales/tr/Common.json?url";
import CommonukUAUrl from "PUBLIC_DIR/locales/uk-UA/Common.json?url";
import CommonviUrl from "PUBLIC_DIR/locales/vi/Common.json?url";
import CommonzhCNUrl from "PUBLIC_DIR/locales/zh-CN/Common.json?url";
const az = new Map([
["Login", LoginazUrl],
["Common", CommonazUrl]
]);
const bg = new Map([
["Login", LoginbgUrl],
["Common", CommonbgUrl]
]);
const cs = new Map([
["Login", LogincsUrl],
["Common", CommoncsUrl]
]);
const de = new Map([
["Login", LogindeUrl],
["Common", CommondeUrl]
]);
const elGR = new Map([
["Login", LoginelGRUrl],
["Common", CommonelGRUrl]
]);
const en = new Map([
["Login", LoginenUrl],
["Common", CommonenUrl]
]);
const es = new Map([
["Login", LoginesUrl],
["Common", CommonesUrl]
]);
const fi = new Map([
["Login", LoginfiUrl],
["Common", CommonfiUrl]
]);
const fr = new Map([
["Login", LoginfrUrl],
["Common", CommonfrUrl]
]);
const it = new Map([
["Login", LoginitUrl],
["Common", CommonitUrl]
]);
const jaJP = new Map([
["Login", LoginjaJPUrl],
["Common", CommonjaJPUrl]
]);
const koKR = new Map([
["Login", LoginkoKRUrl],
["Common", CommonkoKRUrl]
]);
const loLA = new Map([
["Login", LoginloLAUrl],
["Common", CommonloLAUrl]
]);
const lv = new Map([
["Login", LoginlvUrl],
["Common", CommonlvUrl]
]);
const nl = new Map([
["Login", LoginnlUrl],
["Common", CommonnlUrl]
]);
const pl = new Map([
["Login", LoginplUrl],
["Common", CommonplUrl]
]);
const pt = new Map([
["Login", LoginptUrl],
["Common", CommonptUrl]
]);
const ptBR = new Map([
["Login", LoginptBRUrl],
["Common", CommonptBRUrl]
]);
const ro = new Map([
["Login", LoginroUrl],
["Common", CommonroUrl]
]);
const ru = new Map([
["Login", LoginruUrl],
["Common", CommonruUrl]
]);
const sk = new Map([
["Login", LoginskUrl],
["Common", CommonskUrl]
]);
const sl = new Map([
["Login", LoginslUrl],
["Common", CommonslUrl]
]);
const tr = new Map([
["Login", LogintrUrl],
["Common", CommontrUrl]
]);
const ukUA = new Map([
["Login", LoginukUAUrl],
["Common", CommonukUAUrl]
]);
const vi = new Map([
["Login", LoginviUrl],
["Common", CommonviUrl]
]);
const zhCN = new Map([
["Login", LoginzhCNUrl],
["Common", CommonzhCNUrl]
]);
export const translations = new Map([
["az", az],
["bg", bg],
["cs", cs],
["de", de],
["el-GR", elGR],
["en", en],
["es", es],
["fi", fi],
["fr", fr],
["it", it],
["ja-JP", jaJP],
["ko-KR", koKR],
["lo-LA", loLA],
["lv", lv],
["nl", nl],
["pl", pl],
["pt", pt],
["pt-BR", ptBR],
["ro", ro],
["ru", ru],
["sk", sk],
["sl", sl],
["tr", tr],
["uk-UA", ukUA],
["vi", vi],
["zh-CN", zhCN],
]);

View File

@ -1,6 +1,6 @@
import React from "react";
import { hydrate } from "react-dom";
import { registerSW } from "@docspace/common/sw/helper";
// import { registerSW } from "@docspace/common/sw/helper";
import pkg from "../../package.json";
import { initI18n } from "./helpers/utils";
import ClientApp from "./components/ClientApp";
@ -55,4 +55,4 @@ if (IS_DEVELOPMENT) {
};
}
registerSW();
// registerSW();

View File

@ -73,8 +73,8 @@ const Form: React.FC = ({ theme, setTheme, logoUrls }) => {
const logo = Object.values(logoUrls)[1];
const logoUrl = !theme?.isBase
? getLogoFromPath(logo?.path?.dark).replace("client/", "/login/")
: getLogoFromPath(logo?.path?.light).replace("client/", "/login/");
? getLogoFromPath(logo?.path?.dark)
: getLogoFromPath(logo?.path?.light);
return (
<LoginContainer id="code-page" theme={theme}>
@ -135,10 +135,7 @@ const Form: React.FC = ({ theme, setTheme, logoUrls }) => {
};
const CodeLogin: React.FC<ICodeProps> = (props) => {
const bgPattern = getBgPattern(props.currentColorScheme.id).replace(
"client/",
"/login/"
);
const bgPattern = getBgPattern(props.currentColorScheme.id);
const mounted = useMounted();
if (!mounted) return <></>;

View File

@ -187,15 +187,12 @@ const Login: React.FC<ILoginProps> = ({
setRecoverDialogVisible(!recoverDialogVisible);
};
const bgPattern = getBgPattern(currentColorScheme.id).replace(
"client/",
"login/"
);
const bgPattern = getBgPattern(currentColorScheme.id);
const logo = Object.values(logoUrls)[1];
const logoUrl = !theme.isBase
? getLogoFromPath(logo.path.dark).replace("client/", "login/")
: getLogoFromPath(logo.path.light).replace("client/", "login/");
? getLogoFromPath(logo.path.dark)
: getLogoFromPath(logo.path.light);
if (!mounted) return <></>;
if (isRestoringPortal) return <></>;

View File

@ -26,8 +26,8 @@ const SimpleNav = ({ theme, logoUrls }) => {
const logo = Object.values(logoUrls)[0];
const logoUrl = !theme.isBase
? getLogoFromPath(logo.path.dark).replace("client/", "/login/")
: getLogoFromPath(logo.path.light).replace("client/", "/login/");
? getLogoFromPath(logo.path.dark)
: getLogoFromPath(logo.path.light);
return (
<StyledNav id="login-header" theme={theme}>

View File

@ -1,10 +1,48 @@
import { translations } from "../../autoGeneratedTranslations";
import pkg from "../../../package.json";
import { thirdPartyLogin } from "@docspace/common/utils/loginUtils";
export function getLanguage(lng: string) {
try {
let language = lng == "en-US" || lng == "en-GB" ? "en" : lng;
const splitted = lng.split("-");
if (splitted.length == 2 && splitted[0] == splitted[1].toLowerCase()) {
language = splitted[0];
}
return language;
} catch (error) {
console.error(error);
}
return lng;
}
export function loadLanguagePath(homepage: string, fixedNS = null) {
return (lng: string | [string], ns: string) => {
const language = getLanguage(lng instanceof Array ? lng[0] : lng);
const lngCollection = translations.get(language);
const path = lngCollection?.get(`${fixedNS || ns}`);
if (!path) return `/login/locales/${language}/${fixedNS || ns}.json`;
const isCommonPath = path?.indexOf("Common") > -1;
if (ns.length > 0 && ns[0] === "Common" && isCommonPath) {
return path.replace("/login/", "/static/");
}
return path;
};
}
export function initI18n(initialI18nStoreASC: IInitialI18nStoreASC): void {
if (!initialI18nStoreASC || window.i18n) return;
const { homepage } = pkg;
const i18n = {
inLoad: [],
loaded: {},
@ -12,17 +50,28 @@ export function initI18n(initialI18nStoreASC: IInitialI18nStoreASC): void {
window.i18n = i18n;
for (let lng in initialI18nStoreASC) {
const collection = translations.get(lng);
for (let ns in initialI18nStoreASC[lng]) {
if (ns === "Common") {
window.i18n.loaded[`/static/locales/${lng}/${ns}.json`] = {
const path = collection?.get(ns);
if (!path) {
window.i18n.loaded[`/login/locales/${lng}/${ns}.json`] = {
namespaces: ns,
data: initialI18nStoreASC[lng][ns],
};
} else {
window.i18n.loaded[`${homepage}/locales/${lng}/${ns}.json`] = {
namespaces: ns,
data: initialI18nStoreASC[lng][ns],
};
if (ns === "Common") {
window.i18n.loaded[`${path?.replace("/login/", "/static/")}`] = {
namespaces: ns,
data: initialI18nStoreASC[lng][ns],
};
} else {
window.i18n.loaded[`${path}`] = {
namespaces: ns,
data: initialI18nStoreASC[lng][ns],
};
}
}
}
}

View File

@ -3,7 +3,8 @@ import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import config from "../../package.json";
import { LANGUAGE } from "@docspace/common/constants";
import { loadLanguagePath, getCookie } from "@docspace/common/utils";
import { getCookie } from "@docspace/common/utils";
import { loadLanguagePath } from "./helpers/utils";
const newInstance = i18n.createInstance();

View File

@ -12,6 +12,7 @@ import i18nextMiddleware from "i18next-express-middleware";
import i18next from "./i18n";
import cookieParser from "cookie-parser";
import { LANGUAGE, COOKIE_EXPIRATION_YEAR } from "@docspace/common/constants";
import { getLanguage } from "@docspace/common/utils";
import { initSSR } from "@docspace/common/api/client";
import dns from "dns";
@ -66,6 +67,8 @@ app.get("*", async (req: ILoginRequest, res: Response, next) => {
});
}
currentLanguage = getLanguage(currentLanguage);
if (i18n) await i18n.changeLanguage(currentLanguage);
let initialI18nStore = {};

View File

@ -1,3 +1,4 @@
import { translations } from "../../../autoGeneratedTranslations";
import path from "path";
import fs from "fs";
import {
@ -37,18 +38,9 @@ export const getScripts = (assets: assetsType): string[] | void => {
};
export const loadPath = (language: string, nameSpace: string): string => {
let resourcePath = path.resolve(
path.join(__dirname, "client", `locales/${language}/${nameSpace}.json`)
);
if (nameSpace === "Common")
resourcePath = path.resolve(
path.join(
__dirname,
`../../../public/locales/${language}/${nameSpace}.json`
)
);
const path = translations?.get(language)?.get(nameSpace);
return resourcePath;
return path;
};
export const getInitialState = async (

View File

@ -2,6 +2,13 @@ import { getScripts } from "./helpers";
import pkg from "../../../package.json";
import { getLogoFromPath } from "@docspace/common/utils";
import firstFont from "PUBLIC_DIR/fonts/RjgO7rYTmqiVp7vzi-Q5URJtnKITppOI_IvcXXDNrsc.woff2";
import secondFont from "PUBLIC_DIR/fonts/MTP_ySUJH_bn48VBG8sNSugdm0LZdjqr5-oayXSOefg.woff2";
import thirdFont from "PUBLIC_DIR/fonts/k3k702ZOKiLJc3WVjuplzOgdm0LZdjqr5-oayXSOefg.woff2";
import fourthFont from "PUBLIC_DIR/fonts/cJZKeOuBrn4kERxqtaUH3VtXRa8TVwTICgirnJhmVJw.woff2";
import fifthFont from "PUBLIC_DIR/fonts/MTP_ySUJH_bn48VBG8sNSpX5f-9o1vgP2EXwfjgl7AY.woff2";
import sixthFont from "PUBLIC_DIR/fonts/k3k702ZOKiLJc3WVjuplzJX5f-9o1vgP2EXwfjgl7AY.woff2";
const { title } = pkg;
const organizationName = "ONLYOFFICE"; //TODO: Replace to API variant
@ -28,9 +35,7 @@ const template: Template = (
? `${t("Authorization")} ${organizationName}`
: title;
const favicon = getLogoFromPath(
initLoginState.logoUrls[2]?.path?.light
).replace("client/", "login/");
const favicon = getLogoFromPath(initLoginState.logoUrls[2]?.path?.light);
let clientScripts =
assets && assets.hasOwnProperty("client.js")
@ -88,12 +93,12 @@ const template: Template = (
content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no, viewport-fit=cover"
/>
<meta name="theme-color" content="#000000" />
<link rel="preload" as="font" crossorigin type="font/woff2" href="/static/fonts/RjgO7rYTmqiVp7vzi-Q5URJtnKITppOI_IvcXXDNrsc.woff2" />
<link rel="preload" as="font" crossorigin type="font/woff2" href="/static/fonts/MTP_ySUJH_bn48VBG8sNSugdm0LZdjqr5-oayXSOefg.woff2" />
<link rel="preload" as="font" crossorigin type="font/woff2" href="/static/fonts/k3k702ZOKiLJc3WVjuplzOgdm0LZdjqr5-oayXSOefg.woff2" />
<link rel="preload" as="font" crossorigin type="font/woff2" href="/static/fonts/cJZKeOuBrn4kERxqtaUH3VtXRa8TVwTICgirnJhmVJw.woff2" />
<link rel="preload" as="font" crossorigin type="font/woff2" href="/static/fonts/MTP_ySUJH_bn48VBG8sNSpX5f-9o1vgP2EXwfjgl7AY.woff2" />
<link rel="preload" as="font" crossorigin type="font/woff2" href="/static/fonts/k3k702ZOKiLJc3WVjuplzJX5f-9o1vgP2EXwfjgl7AY.woff2" />
<link rel="preload" as="font" crossorigin type="font/woff2" href="${firstFont}" />
<link rel="preload" as="font" crossorigin type="font/woff2" href="${secondFont}" />
<link rel="preload" as="font" crossorigin type="font/woff2" href="${thirdFont}" />
<link rel="preload" as="font" crossorigin type="font/woff2" href="${fourthFont}" />
<link rel="preload" as="font" crossorigin type="font/woff2" href="${fifthFont}" />
<link rel="preload" as="font" crossorigin type="font/woff2" href="${sixthFont}" />
<link id="favicon" rel="shortcut icon" href=${favicon} />
<link rel="manifest" href="/manifest.json" />

View File

@ -14,6 +14,7 @@ module.exports = {
},
alias: {
PUBLIC_DIR: path.resolve(__dirname, "../../../public"),
ASSETS_DIR: path.resolve(__dirname, "../public"),
SRC_DIR: path.resolve(__dirname, "../src"),
PACKAGE_FILE: path.resolve(__dirname, "../package.json"),
},
@ -44,15 +45,24 @@ module.exports = {
},
{
test: fontsExtension,
type: "asset",
generator: {
emit: false,
},
type: "asset/resource",
},
{
test: /\.(png|jpe?g|gif|ico)$/i,
generator: {
emit: false,
},
type: "asset/resource",
},
{
test: /\.svg$/i,
type: "asset/resource",
generator: {
emit: false,
},
resourceQuery: /url/, // *.svg?url
},
{
@ -72,6 +82,9 @@ module.exports = {
},
{
test: imageExtensions,
generator: {
emit: false,
},
type: "asset/resource",
},
],

View File

@ -11,6 +11,8 @@ const TerserPlugin = require("terser-webpack-plugin");
const combineUrl = require("@docspace/common/utils/combineUrl");
const minifyJson = require("@docspace/common/utils/minifyJson");
const sharedDeps = require("@docspace/common/constants/sharedDependencies");
const PrebuildWebpackPlugin = require("prebuild-webpack-plugin");
const beforeBuild = require("@docspace/common/utils/beforeBuild");
const baseConfig = require("./webpack.base.js");
const pkg = require("../package.json");
const deps = pkg.dependencies || {};
@ -44,7 +46,7 @@ const clientConfig = {
folder += result.length === 0 ? "" : "/";
return `${folder}[name][ext]?hash=[contenthash]`; // `${folder}/[name].[contenthash][ext]`;
return `static/${folder}[name][ext]?hash=[contenthash]`; // `${folder}/[name].[contenthash][ext]`;
},
},
@ -82,6 +84,33 @@ const clientConfig = {
"sass-loader",
],
},
{
test: /\.json$/,
resourceQuery: /url/,
type: "javascript/auto",
use: [
{
loader: "file-loader",
options: {
emitFile: false,
name: (resourcePath, resourceQuery) => {
let result = resourcePath
.split(`public${path.sep}`)[1]
.split(path.sep);
result.pop();
let folder = result.join("/");
folder += result.length === 0 ? "" : "/";
return `${folder}[name].[ext]?hash=[contenthash]`; // `${folder}/[name].[contenthash][ext]`;
},
},
},
],
},
],
},
@ -110,6 +139,17 @@ const clientConfig = {
],
}),
new WebpackManifestPlugin(),
new PrebuildWebpackPlugin({
build: async (compiler, compilation, matchedFiles) => {
await beforeBuild(
[
path.join(__dirname, "../public/locales"),
path.join(__dirname, "../../../public/locales"),
],
path.join(__dirname, "../src/autoGeneratedTranslations.ts")
);
},
}),
],
};

View File

@ -31,10 +31,42 @@ const serverConfig = {
folder += result.length === 0 ? "" : "/";
return `client/${folder}[name][ext]?hash=[contenthash]`; //`${folder}/[name].[contenthash][ext]`;
return `/login/static/${folder}[name][ext]?hash=[contenthash]`; //`${folder}/[name].[contenthash][ext]`;
},
},
module: {
rules: [
{
test: /\.json$/,
resourceQuery: /url/,
type: "javascript/auto",
use: [
{
loader: "file-loader",
options: {
emitFile: false,
name: (resourcePath) => {
let result = resourcePath
.split(`public${path.sep}`)[1]
.split(path.sep);
result.pop();
let folder = result.join("/");
folder += result.length === 0 ? "" : "/";
return `client/${folder}[name].[ext]?hash=[contenthash]`; // `${folder}/[name].[contenthash][ext]`;
},
},
},
],
},
],
},
plugins: [
new CopyPlugin({
patterns: [

View File

@ -892,7 +892,7 @@ public class FileStorageService<T> //: IFileStorageService
{
var pathThumb = $"{path}{fileExt.Trim('.')}.{size.Width}x{size.Height}.{_global.ThumbnailExtension}";
if (await storeTemplate.IsFileAsync("", pathThumb))
if (!await storeTemplate.IsFileAsync("", pathThumb))
{
break;
}

View File

@ -43,11 +43,20 @@ public class ThumbnailSettings
set => _serverRoot = value;
}
private int _launchFrequency;
public int LaunchFrequency
private int _boundedChannelCapacity;
public int BoundedChannelCapacity
{
get => _launchFrequency != 0 ? _launchFrequency : 15;
set => _launchFrequency = value;
get => _boundedChannelCapacity != 0 ? _boundedChannelCapacity : MaxDegreeOfParallelism * 10;
set => _boundedChannelCapacity = value;
}
private int _batchSize;
public int BatchSize
{
get => _batchSize != 0 ? _batchSize : MaxDegreeOfParallelism * 10;
set => _batchSize = value;
}
#endregion

View File

@ -89,8 +89,11 @@ internal class FileConverterService<T> : BackgroundService
fileConverterQueue = scope.ServiceProvider.GetService<FileConverterQueue<T>>();
var _conversionQueue = fileConverterQueue.GetAllTask().ToList();
logger.DebugRunCheckConvertFilesStatus(_conversionQueue.Count);
if (_conversionQueue.Count > 0)
{
logger.DebugRunCheckConvertFilesStatus(_conversionQueue.Count);
}
var filesIsConverting = _conversionQueue
.Where(x => string.IsNullOrEmpty(x.Processed))

View File

@ -48,6 +48,9 @@ internal static partial class BuilderLogger
[LoggerMessage(Level = LogLevel.Debug, Message = "CropImage: FileId: {fileId}. Successfully saved.")]
public static partial void DebugCropImageSuccessfullySaved(this ILogger logger, string fileId);
[LoggerMessage(Level = LogLevel.Warning, Message = "MakeThumbnail: FileId: {fileId}, ThumbnailUrl: {url}, ResultPercent: {percent}, Attempt: {attempt}. Exception in process generate document thumbnails")]
public static partial void WarningMakeThumbnail(this ILogger logger, string fileId, string url, int percent, int attempt, Exception exception);
[LoggerMessage(Level = LogLevel.Error, Message = "BuildThumbnails: filesWithoutThumbnails.Count: {count}.")]
public static partial void ErrorBuildThumbnailsCount(this ILogger logger, int count, Exception exception);

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using System.Threading.Channels;
namespace ASC.Files.Service;
public class Startup : BaseWorkerStartup
{
@ -65,9 +67,7 @@ public class Startup : BaseWorkerStartup
services.AddHostedService<FeedCleanerService>();
DIHelper.TryAdd<FeedCleanerService>();
DIHelper.TryAdd<FileDataQueue>();
services.AddActivePassiveHostedService<FileConverterService<int>>();
DIHelper.TryAdd<FileConverterService<int>>();
@ -93,6 +93,9 @@ public class Startup : BaseWorkerStartup
DIHelper.TryAdd<UserManager>();
DIHelper.TryAdd<SocketServiceClient>();
DIHelper.TryAdd<FileStorageService<int>>();
DIHelper.TryAdd<FileDataProvider>();
DIHelper.TryAdd<BuilderQueue<int>>();
DIHelper.TryAdd<Builder<int>>();
services.AddScoped<ITenantQuotaFeatureChecker, CountRoomChecker>();
services.AddScoped<CountRoomChecker>();
@ -103,12 +106,20 @@ public class Startup : BaseWorkerStartup
services.AddScoped<UsersInRoomChecker>();
services.AddScoped<ITenantQuotaFeatureStat<UsersInRoomFeature, int>, UsersInRoomStatistic>();
services.AddScoped<UsersInRoomStatistic>();
services.AddBaseDbContextPool<FilesDbContext>();
services.AddBaseDbContextPool<FilesDbContext>();
if (!int.TryParse(_configuration["thumbnail:boundedChannelCapacity"], out var boundedChannelCapacity))
{
boundedChannelCapacity = 100;
}
services.AddSingleton(Channel.CreateBounded<IEnumerable<FileData<int>>>(new BoundedChannelOptions(boundedChannelCapacity) { SingleReader = true, SingleWriter = false }));
services.AddSingleton(svc => svc.GetRequiredService<Channel<IEnumerable<FileData<int>>>>().Reader);
services.AddSingleton(svc => svc.GetRequiredService<Channel<IEnumerable<FileData<int>>>>().Writer);
}
}

View File

@ -46,6 +46,17 @@ public class BuilderQueue<T>
{
try
{
await using var scope = _serviceScopeFactory.CreateAsyncScope();
var fileDataProvider = scope.ServiceProvider.GetService<FileDataProvider>();
var premiumTenants = fileDataProvider.GetPremiumTenants();
filesWithoutThumbnails = filesWithoutThumbnails
.OrderByDescending(fileData => Array.IndexOf(premiumTenants, fileData.TenantId))
.ToList();
await Parallel.ForEachAsync(
filesWithoutThumbnails,
new ParallelOptions { MaxDegreeOfParallelism = _config.MaxDegreeOfParallelism },
@ -141,11 +152,7 @@ public class Builder<T>
catch (Exception exception)
{
_logger.ErrorBuildThumbnailsTenantId(fileData.TenantId, exception);
}
finally
{
FileDataQueue.Queue.TryRemove(fileData.FileId, out _);
}
}
}
private async Task GenerateThumbnail(IFileDao<T> fileDao, FileData<T> fileData)
@ -240,22 +247,22 @@ public class Builder<T>
private async Task MakeThumbnail(IFileDao<T> fileDao, File<T> file)
{
await fileDao.SetThumbnailStatusAsync(file, Core.Thumbnail.Creating);
foreach (var w in _config.Sizes)
{
_logger.DebugMakeThumbnail1(file.Id.ToString());
string thumbnailUrl = null;
var resultPercent = 0;
var attempt = 1;
do
{
try
{
var (result, url) = await GetThumbnailUrl(file, _global.DocThumbnailExtension.ToString(), w.Width, w.Height);
thumbnailUrl = url;
if (result)
(resultPercent, thumbnailUrl) = await GetThumbnailUrl(file, _global.DocThumbnailExtension.ToString(), w.Width, w.Height);
if (resultPercent == 100)
{
break;
}
@ -269,19 +276,27 @@ public class Builder<T>
{
if (documentServiceException.Code == DocumentServiceException.ErrorCode.ConvertPassword)
{
throw new Exception(string.Format("MakeThumbnail: FileId: {0}. Encrypted file.", file.Id));
throw new Exception(String.Format("MakeThumbnail: FileId: {0}. Encrypted file.", file.Id), exception);
}
if (documentServiceException.Code == DocumentServiceException.ErrorCode.Convert)
{
throw new Exception(string.Format("MakeThumbnail: FileId: {0}. Could not convert.", file.Id));
throw new Exception(String.Format("MakeThumbnail: FileId: {0}. Could not convert.", file.Id), exception);
}
}
else
{
_logger.WarningMakeThumbnail(file.Id.ToString(), thumbnailUrl, resultPercent, attempt, exception);
}
}
else
{
_logger.WarningMakeThumbnail(file.Id.ToString(), thumbnailUrl, resultPercent, attempt, exception);
}
}
if (attempt >= _config.AttemptsLimit)
{
throw new Exception(string.Format("MakeThumbnail: FileId: {0}. Attempts limmit exceeded.", file.Id));
throw new Exception(string.Format("MakeThumbnail: FileId: {0}, ThumbnailUrl: {1}, ResultPercent: {2}. Attempts limmit exceeded.", file.Id, thumbnailUrl, resultPercent));
}
else
{
@ -300,7 +315,7 @@ public class Builder<T>
}
private async Task<(bool, string)> GetThumbnailUrl(File<T> file, string toExtension, int width, int height)
private async Task<(int, string)> GetThumbnailUrl(File<T> file, string toExtension, int width, int height)
{
var fileUri = _pathProvider.GetFileStreamUrl(file);
fileUri = _documentServiceConnector.ReplaceCommunityAdress(fileUri);
@ -337,7 +352,7 @@ public class Builder<T>
var (operationResultProgress, url) = await _documentServiceConnector.GetConvertedUriAsync(fileUri, fileExtension, toExtension, docKey, null, CultureInfo.CurrentCulture.Name, thumbnail, spreadsheetLayout, false);
operationResultProgress = Math.Min(operationResultProgress, 100);
return (operationResultProgress == 100, url);
return (operationResultProgress, url);
}
private async Task SaveThumbnail(IFileDao<T> fileDao, File<T> file, string thumbnailUrl, int width, int height)

View File

@ -29,7 +29,7 @@ using Microsoft.EntityFrameworkCore;
namespace ASC.Files.ThumbnailBuilder;
[Scope]
internal class FileDataProvider
public class FileDataProvider
{
private readonly ThumbnailSettings _thumbnailSettings;
private readonly ICache _cache;

View File

@ -1,34 +0,0 @@
// (c) Copyright Ascensio System SIA 2010-2022
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
namespace ASC.Files.ThumbnailBuilder;
[Singletone(Additional = typeof(WorkerExtension))]
public class FileDataQueue
{
internal static readonly ConcurrentDictionary<object, FileData<int>> Queue
= new ConcurrentDictionary<object, FileData<int>>();
}

View File

@ -24,22 +24,34 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using System.Threading.Channels;
using ASC.Files.ThumbnailBuilder;
namespace ASC.Thumbnail.IntegrationEvents.EventHandling;
[Scope]
public class ThumbnailRequestedIntegrationEventHandler : IIntegrationEventHandler<ThumbnailRequestedIntegrationEvent>
{
private readonly ILogger _logger;
private readonly ILogger _logger;
private readonly ChannelWriter<IEnumerable<FileData<int>>> _channelWriter;
private readonly FileDataProvider _fileDataProvider;
private ThumbnailRequestedIntegrationEventHandler() : base()
{
}
public ThumbnailRequestedIntegrationEventHandler(ILogger<ThumbnailRequestedIntegrationEventHandler> logger)
public ThumbnailRequestedIntegrationEventHandler(
ILogger<ThumbnailRequestedIntegrationEventHandler> logger,
FileDataProvider fileDataProvider,
ChannelWriter<IEnumerable<FileData<int>>> channelWriter)
{
_logger = logger;
}
_logger = logger;
_channelWriter = channelWriter;
_fileDataProvider = fileDataProvider;
}
public async Task Handle(ThumbnailRequestedIntegrationEvent @event)
{
@ -47,14 +59,15 @@ public class ThumbnailRequestedIntegrationEventHandler : IIntegrationEventHandle
{
_logger.InformationHandlingIntegrationEvent(@event.Id, Program.AppName, @event);
foreach (var fileId in @event.FileIds)
var freezingThumbnails = await _fileDataProvider.GetFreezingThumbnailsAsync();
var rawData = @event.FileIds.Select(fileId => new FileData<int>(@event.TenantId, Convert.ToInt32(fileId), @event.BaseUrl))
.Union(freezingThumbnails);
if (await _channelWriter.WaitToWriteAsync())
{
var fileData = new FileData<int>(@event.TenantId, Convert.ToInt32(fileId), @event.BaseUrl);
FileDataQueue.Queue.TryAdd(fileId, fileData);
await _channelWriter.WriteAsync(rawData);
}
await Task.CompletedTask;
}
}
}

View File

@ -24,6 +24,8 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
using System.Threading.Channels;
namespace ASC.Files.ThumbnailBuilder;
[Singletone]
@ -33,80 +35,49 @@ public class ThumbnailBuilderService : BackgroundService
private readonly ThumbnailSettings _thumbnailSettings;
private readonly ILogger<ThumbnailBuilderService> _logger;
private readonly BuilderQueue<int> _builderQueue;
private readonly ChannelReader<IEnumerable<FileData<int>>> _channelReader;
public ThumbnailBuilderService(
BuilderQueue<int> builderQueue,
IServiceScopeFactory serviceScopeFactory,
ILogger<ThumbnailBuilderService> logger,
ThumbnailSettings settings)
ThumbnailSettings settings,
ChannelReader<IEnumerable<FileData<int>>> channelReader)
{
_serviceScopeFactory = serviceScopeFactory;
_thumbnailSettings = settings;
_logger = logger;
_builderQueue = builderQueue;
_channelReader = channelReader;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.InformationThumbnailWorkerRunnig();
stoppingToken.Register(() => _logger.InformationThumbnailWorkerStopping());
var fetchedData = new List<FileData<int>>();
while (!stoppingToken.IsCancellationRequested)
{
await Procedure(stoppingToken);
_logger.TraceProcedureStart();
await foreach (var rawData in _channelReader.ReadAllAsync(stoppingToken))
{
fetchedData.AddRange(rawData);
if (_channelReader.CanCount && _channelReader.Count > 0 && _thumbnailSettings.BatchSize >= fetchedData.Count())
{
continue;
}
await _builderQueue.BuildThumbnails(fetchedData);
fetchedData = new List<FileData<int>>();
}
}
_logger.InformationThumbnailWorkerStopping();
}
private async Task Procedure(CancellationToken stoppingToken)
{
_logger.TraceProcedureStart();
if (stoppingToken.IsCancellationRequested)
{
return;
}
//var configSection = (ConfigSection)ConfigurationManager.GetSection("thumbnailBuilder") ?? new ConfigSection();
//CommonLinkUtility.Initialize(configSection.ServerRoot, false);
await using (var scope = _serviceScopeFactory.CreateAsyncScope())
{
var fileDataProvider = scope.ServiceProvider.GetService<FileDataProvider>();
var filesWithoutThumbnails = FileDataQueue.Queue.Select(pair => pair.Value)
.ToList();
filesWithoutThumbnails.AddRange(await fileDataProvider.GetFreezingThumbnailsAsync());
if (filesWithoutThumbnails.Count == 0)
{
_logger.TraceProcedureWaiting(_thumbnailSettings.LaunchFrequency);
await Task.Delay(TimeSpan.FromSeconds(_thumbnailSettings.LaunchFrequency), stoppingToken);
return;
}
var premiumTenants = fileDataProvider.GetPremiumTenants();
filesWithoutThumbnails = filesWithoutThumbnails
.OrderByDescending(fileData => Array.IndexOf(premiumTenants, fileData.TenantId))
.ToList();
await _builderQueue.BuildThumbnails(filesWithoutThumbnails);
}
_logger.TraceProcedureFinish();
}
}
public static class WorkerExtension
{
public static void Register(DIHelper services)
{
services.TryAdd<FileDataProvider>();
services.TryAdd<BuilderQueue<int>>();
services.TryAdd<Builder<int>>();
}
}

View File

@ -2798,6 +2798,7 @@ __metadata:
html-webpack-plugin: 5.3.2
json-loader: ^0.5.7
playwright: ^1.18.1
prebuild-webpack-plugin: ^1.1.1
react-avatar-editor: ^13.0.0
react-colorful: ^5.5.1
react-hotkeys-hook: ^3.4.4
@ -2987,6 +2988,7 @@ __metadata:
nconf: ^0.12.0
nodemon: ^2.0.7
npm-run-all: ^4.1.5
prebuild-webpack-plugin: ^1.1.1
sass: ^1.53.0
sass-loader: ^13.0.2
shx: ^0.3.4
@ -3061,6 +3063,7 @@ __metadata:
nodemon: ^2.0.19
npm-run-all: ^4.1.5
playwright: ^1.17.1
prebuild-webpack-plugin: ^1.1.1
sass: ^1.39.2
sass-loader: ^12.1.0
serve: 14.1.1
@ -14030,7 +14033,7 @@ __metadata:
languageName: node
linkType: hard
"glob@npm:^7.0.0, glob@npm:^7.0.3, glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.2.0":
"glob@npm:^7.0.0, glob@npm:^7.0.3, glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.5, glob@npm:^7.1.6, glob@npm:^7.2.0":
version: 7.2.3
resolution: "glob@npm:7.2.3"
dependencies:
@ -20302,6 +20305,17 @@ __metadata:
languageName: node
linkType: hard
"prebuild-webpack-plugin@npm:^1.1.1":
version: 1.1.1
resolution: "prebuild-webpack-plugin@npm:1.1.1"
dependencies:
debug: ^4.1.1
glob: ^7.1.5
minimatch: ^3.0.4
checksum: 11e091bbefc8e3dcda84c6abd1d02e250af4f4a5189355464bb5b440de2c6da722a55956b190ca6e4a4136684f0643d16c7d5c48a6eeae9b670409d62e1c6047
languageName: node
linkType: hard
"prefix-style@npm:2.0.1":
version: 2.0.1
resolution: "prefix-style@npm:2.0.1"